当前位置: 首页 > 面试题库 >

通过与BouncyCastle进行CSR签名生成的证书被视为不可信

丌官寒
2023-03-14
问题内容

我正在努力解决以下问题:

我有一个使用此代码签名的CSR:

@Override
public X509Certificate signCSR( Reader pemcsr, int validityDays ) throws APIException
{
try ( PEMParser reader = new PEMParser( pemcsr ) )
{

  KeyStore keystore = getKeyStore();

  Properties cryptoProps = getCryptoProperties();

  String caKeyAlias = cryptoProps.getProperty( PROPERTY_KEYSTORE_CA_CERT_ALIAS );
  String caKeyPassword = cryptoProps.getProperty( PROPERTY_KEYSTORE_CA_CERT_PASSWORD );

  PrivateKey cakey = (PrivateKey) keystore.getKey( caKeyAlias, caKeyPassword.toCharArray() );
  X509Certificate cacert = (X509Certificate) keystore.getCertificate( caKeyAlias );

  PKCS10CertificationRequest csr = (PKCS10CertificationRequest) reader.readObject();

  AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find( "SHA1withRSA" );
  AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find( sigAlgId );
  X500Name issuer = new X500Name( cacert.getSubjectX500Principal().getName() );
  BigInteger serial = new BigInteger( 32, new SecureRandom() );
  Date from = new Date();
  Date to = new Date( System.currentTimeMillis() + ( validityDays * 86400000L ) );

  DigestCalculator digCalc = new BcDigestCalculatorProvider().get( new AlgorithmIdentifier( OIWObjectIdentifiers.idSHA1 ) );
  X509ExtensionUtils x509ExtensionUtils = new X509ExtensionUtils( digCalc );

  X509v3CertificateBuilder certgen = new X509v3CertificateBuilder( issuer, serial, from, to, csr.getSubject(), csr.getSubjectPublicKeyInfo() );

  // Basic Constraints
  // certgen.addExtension( Extension.basicConstraints, true, new
  // BasicConstraints( 0 ) );

  // Subject Key Identifier
  // certgen.addExtension( Extension.subjectKeyIdentifier, false,
  // x509ExtensionUtils.createSubjectKeyIdentifier(
  // csr.getSubjectPublicKeyInfo() ) );

  // Authority Key Identifier
  // byte[] caKeyEncoded = cacert.getPublicKey().getEncoded();
  // SubjectPublicKeyInfo caSubjectPublicKeyInfo =
  // SubjectPublicKeyInfo.getInstance( caKeyEncoded );
  // certgen.addExtension( Extension.authorityKeyIdentifier, false,
  // x509ExtensionUtils.createAuthorityKeyIdentifier( caSubjectPublicKeyInfo
  // ) );

  // Key Usage
  // certgen.addExtension( Extension.keyUsage, false, new KeyUsage(
  // KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign )
  // );

  ContentSigner signer = new BcRSAContentSignerBuilder( sigAlgId, digAlgId ).build( PrivateKeyFactory.createKey( cakey.getEncoded() ) );

  // ContentSigner signer = new JcaContentSignerBuilder(
  // "SHA1WithRSAEncryption" ).html" target="_blank">setProvider( "BC" ).build( cakey );

  X509CertificateHolder holder = certgen.build( signer );

  return new JcaX509CertificateConverter().setProvider( "BC" ).getCertificate( holder );
}
catch ( NoSuchAlgorithmException | KeyStoreException | CertificateException | OperatorCreationException | UnrecoverableKeyException | CertIOException e )
{
  throw new APIException( API_ERROR_CODE.CRYPTOGRAPHY_ERROR, e );
}
catch ( IOException e )
{
  throw new APIException( API_ERROR_CODE.IO_ERROR, e );
}

}

这将成功运行。但是,当我尝试使用以下方法检查密钥时:

KeyStore ks = getKeyStore();

  TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm() );
  trustManagerFactory.init( ks );

  for ( TrustManager trustManager : trustManagerFactory.getTrustManagers() )
  {
    if ( trustManager instanceof X509TrustManager )
    {
      X509TrustManager x509TrustManager = (X509TrustManager) trustManager;
      x509TrustManager.checkClientTrusted( new X509Certificate[] { certificate }, "RSA" );
    }
  }

…它失败并出现CertificateException。请注意,我在这里使用VERY
SAME密钥库,这意味着与我签名的CA密钥包含在其中。为什么会这样?

顺便说一句,很奇怪,当我使用Windows的证书查看器打开生成的签名证书时,它确实显示了颁发CA的名称,但其条目未显示在证书链中。似乎Windows可信度列表中不存在CA根证书,但实际上它也在那里。

甚至更陌生:如果我使用OpenSSL签署CSR,则证书链看起来还可以。我还认为,通过PKCS12将CA密钥对从OpenSSL导入到Java密钥库作为中间格式是不成功的,但是实际上,如果我从Java密钥库导出CA证书并使用Windows证书打开它查看器,它显示为受信任的…

更新:
对于熟悉ASN.1的人,这里有两个编码证书。一个是用BouncyCastle制作的,不受信任,另一个是用OpenSSL的同一CA密钥签名的,并且是受信任的。可以使用如下工具对它们进行解码:ASN.1解码器非常感谢有人可以查看此解码数据并告诉我是什么原因导致它们之间的差异。

这是不可信的:

-----BEGIN CERTIFICATE-----
MIIC6TCCAlKgAwIBAgIESdsI/TANBgkqhkiG9w0BAQUFADCBgzEgMB4GCSqGSIb3
DQEJARYRdGVzdGNhQHRlc3RjYS5jb20xEDAOBgNVBAMMB1Rlc3QgQ0ExEDAOBgNV
BAsMB1Rlc3QgQ0ExEDAOBgNVBAoMB1Rlc3QgQ0ExDTALBgNVBAcMBFdpZW4xDTAL
BgNVBAgMBFdpZW4xCzAJBgNVBAYTAkFUMB4XDTE0MDUxOTExNTYwM1oXDTE1MDUx
OTExNTYwM1owajELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAlBiMQswCQYDVQQHEwJC
cDETMBEGA1UEChMKZmdmZ2ZnZGZnZDEPMA0GA1UECxMGYWJjZGVmMRswGQYDVQQD
DBJwZXRlcnZlbG9zeV90aWdyaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCdL7taENsONBazc2iMDV5nw9ACP5mevmnzPwOJRUcd5GlGgry/iSa3tTwL
l6Um3zNc4X0m5nVVskKeJE4dTvYFV3+vJlEKCra86yQfa6XkGllU4EG6SdG8lRhE
Btk1QbOQZKrUz77IdOWWOUvIsNxtDDQcUhnrSjSxHohdoe/yoCl+60RBdjrgUrRo
uctSHFPvVt2uZaVM2rAVovx56vvJHOag2++rcvXaOh9WHvdwRAIZt/4aOv2O4jdI
jKdRrmF8dOudjR89wIeVjX9fvyvx+hw+ZolUio9GOVKLlBcYno6lEupHLUDK9ECs
W8F6y65nYGlm9/0G0+gB7K1yy1dBAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAKJpM
7AbkWBH3ho1YV0d1glJvefQ1xaXGpDfd+Tzf3+cR1o3+YxxEyuYvBbiQ/MBxKD9/
hsFCqEWzOfu2lAZ+/6uHvt7BCEGhaLdWKXehoaIw/kEMeISIUDFbKORCsKJNbYRB
xgqBXGglTQ4gVXMDRBxzOmButN31j1VDt55gvn4=
-----END CERTIFICATE-----

这是可信任的,它是使用理论上相同的CA证书通过OpenSSL生成的:

-----BEGIN CERTIFICATE-----
MIIC+TCCAmICAhI4MA0GCSqGSIb3DQEBBQUAMIGDMQswCQYDVQQGEwJBVDENMAsG
A1UECAwEV2llbjENMAsGA1UEBwwEV2llbjEQMA4GA1UECgwHVGVzdCBDQTEQMA4G
A1UECwwHVGVzdCBDQTEQMA4GA1UEAwwHVGVzdCBDQTEgMB4GCSqGSIb3DQEJARYR
dGVzdGNhQHRlc3RjYS5jb20wHhcNMTQwNTE0MTkzMTAzWhcNMTUwNTA5MTkzMTAz
WjCBgDELMAkGA1UEBhMCSFUxETAPBgNVBAgTCEJ1ZGFwZXN0MREwDwYDVQQHEwhC
dWRhcGVzdDEWMBQGA1UEChMNTWVyY2hhbnQgVGVzdDEWMBQGA1UECxMNTWVyY2hh
bnQgVGVzdDEbMBkGA1UEAwwScGV0ZXJ2ZWxvc3lfdGlncmlzMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1vuY4MQ5b9Jb0MiyEuCrR4E+7VgmrvEwlswO
aMIF4H6i538PwPml5dbqx/3whxR/BcQJuJYWI/Hh7xxGS7FvSQ+DNhzxv9TpECKS
/5OZNm+JikPZwTiwrS/Cf4NP+ZcXOjtVZp6ngVtTarn3NC/J7gJVYaHVVO4NbUkt
kCYhdfCXg71QiJ42RWMjMC9tJFrrlfem+SVzh8yMtUCBKm7nbMjQ6LngawjTzDK8
2Zcdqwdzvt2pcYcsYSViO5j5t/r7rIDGjRkjJqRSEiJMOvn0W+sdTdmFoZbyj7Qe
pgyCyf28uFyCO9QZro337D8klPLXaWJOwPDXXiuYOTDYAjBVbwIDAQABMA0GCSqG
SIb3DQEBBQUAA4GBAGU60GVjR+2oEiJMSe1CKU7gf+bGuxaCxXQTzVQLU652i1sp
Fv56o6jnLtw46/rQydNKX4GBH022B/BDEPAQQiQv31YKQAoWtBZod0SRonogcx7p
AULacoma9QEgHSX0l+2yEn42/qo7o0pAmmewJlsCnHVIqI0eU8x1XbCEAf53
-----END CERTIFICATE-----

更新2:

感谢Bruno的回答,证书链现在看起来正常,并生成了以下证书:

-----BEGIN CERTIFICATE-----
MIIC6TCCAlKgAwIBAgIEI2vbpTANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
QVQxDTALBgNVBAgMBFdpZW4xDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoMB1Rlc3Qg
Q0ExEDAOBgNVBAsMB1Rlc3QgQ0ExEDAOBgNVBAMMB1Rlc3QgQ0ExIDAeBgkqhkiG
9w0BCQEWEXRlc3RjYUB0ZXN0Y2EuY29tMB4XDTE0MDUyMDA3MzkyMFoXDTE1MDUy
MDA3MzkyMFowajELMAkGA1UEBhMCVUsxCzAJBgNVBAgTAlBiMQswCQYDVQQHEwJC
cDETMBEGA1UEChMKZmdmZ2ZnZGZnZDEPMA0GA1UECxMGYWJjZGVmMRswGQYDVQQD
DBJwZXRlcnZlbG9zeV90aWdyaXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQCdL7taENsONBazc2iMDV5nw9ACP5mevmnzPwOJRUcd5GlGgry/iSa3tTwL
l6Um3zNc4X0m5nVVskKeJE4dTvYFV3+vJlEKCra86yQfa6XkGllU4EG6SdG8lRhE
Btk1QbOQZKrUz77IdOWWOUvIsNxtDDQcUhnrSjSxHohdoe/yoCl+60RBdjrgUrRo
uctSHFPvVt2uZaVM2rAVovx56vvJHOag2++rcvXaOh9WHvdwRAIZt/4aOv2O4jdI
jKdRrmF8dOudjR89wIeVjX9fvyvx+hw+ZolUio9GOVKLlBcYno6lEupHLUDK9ECs
W8F6y65nYGlm9/0G0+gB7K1yy1dBAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAIdFF
h6uLY7ioKQ3O0c4cZHHjRA0HTlWjih8P2xvXY/V9jF914BT7OW52UJ16tQaJlOf+
mAeeBDq9srKnkmOQp3mCejVnkyVZF8pOOzNbqSVzylt0Csg2twnxZ0NcM63Oda5b
YSQI8+arryxykLWkHWH8i/6rPCDCtbAHBo7fSeQ=
-----END CERTIFICATE-----

但是,上面的TrustManager代码将拒绝它。如果我绕开TrustManager并执行以下操作:

 KeyStore ks = getKeyStore();

  Enumeration<String> aliases = ks.aliases();

  while ( aliases.hasMoreElements() )
  {
    String alias = aliases.nextElement();
    Certificate currentCert = ks.getCertificate( alias );
    try
    {
      certificate.verify( currentCert.getPublicKey() );
      return true;
    }
    catch ( Exception e )
    {
      // the certificate cannot be verified with this key.
    }
  }

  return false;

…通过。有人知道为什么它在TrustManager检查中失败吗?

Ps CA证书如下所示:

-----BEGIN CERTIFICATE-----
MIICfzCCAegCCQCU+Ah6M5qQGTANBgkqhkiG9w0BAQUFADCBgzELMAkGA1UEBhMC
QVQxDTALBgNVBAgMBFdpZW4xDTALBgNVBAcMBFdpZW4xEDAOBgNVBAoMB1Rlc3Qg
Q0ExEDAOBgNVBAsMB1Rlc3QgQ0ExEDAOBgNVBAMMB1Rlc3QgQ0ExIDAeBgkqhkiG
9w0BCQEWEXRlc3RjYUB0ZXN0Y2EuY29tMB4XDTE0MDQyMzA3MjYzNFoXDTI0MDQy
MDA3MjYzNFowgYMxCzAJBgNVBAYTAkFUMQ0wCwYDVQQIDARXaWVuMQ0wCwYDVQQH
DARXaWVuMRAwDgYDVQQKDAdUZXN0IENBMRAwDgYDVQQLDAdUZXN0IENBMRAwDgYD
VQQDDAdUZXN0IENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0Y2FAdGVzdGNhLmNvbTCB
nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAldKTo8iqF52dsOwln0Oppu+ODiaG
R4T7Znrca4Cs5FBQOmuMwqUP6ilW115p/WvkBHhm8dZyVACPKdshEfhh4VFAW5r2
mJnosYgjafQpTEv83sc938DwtK6iikZ0uvdBJKG/IuYblNq9TPMLFeTYjD8mgf9j
m6JOvA/Q9J4nRW0CAwEAATANBgkqhkiG9w0BAQUFAAOBgQB8ACYeC+zjV/KqxPr1
cyzfJP9xfUnxDTEKUJS2YVuxJqpfbHeUtvKoN89BfY07XWdnj8cgMDfJp10Kdc2A
clwP2lVDtOgHZS07UUW98q9FKQ33mLHIn0nDKNwTo5VH8t/NJVeMFuZPAbFiI2gj
KH2sTU2GNNvKC4jHh0PS+OZFtg==
-----END CERTIFICATE-----

问题答案:

如果您查看两个证书中的颁发者DN,则它们不匹配(来自的输出openssl x509 -text):

Issuer: C=AT, ST=Wien, L=Wien, O=Test CA, OU=Test CA, CN=Test CA/emailAddress=testca@testca.com

Issuer: emailAddress=testca@testca.com, CN=Test CA, OU=Test CA, O=Test CA, L=Wien, ST=Wien, C=AT

结果,它无法将错误的颁发者与CA的主题DN相匹配。

不幸的是,X500Name issuer = new X500Name(cacert.getSubjectX500Principal().getName())并没有达到您的期望。RDN的顺序相反。通常,由于存在多种将ASN.1表示序列化为字符串的方法,因此从字符串表示重建DN可能会失败。Java
X500Principal具有多种可用格式getName(...),甚至提供了一种为字符串映射提供您自己的OID的方法(对于更加晦涩的OID)。该方法emailAddress被分离也会造成问题(注意它是用逗号或用斜杠分隔的方式)。

而是从编码形式构建X500Name,这应该始终有效:

X500Name x500Name = X500Name.getInstance(cert
                        .getSubjectX500Principal().getEncoded());


 类似资料:
  • 我是否能够使用Android或BouncyCastle libs从CA签名的X509客户端证书中提取证书链信息? 我有一个Android客户端,它从受信任的服务器接收CA签名的X509证书。我想将签名的客户端证书和我的私钥保存到PKCS12(. p12)文件中。我目前正在通过创建一个对象并添加证书和私钥来执行此操作。当我使用方法添加客户端时,是最后一个参数,它当前仅包含客户端证书。这是否会阻止我的

  • 本文档提供使用 openssl 生成自签名证书的一个示例,用户也可以根据自己的需求生成符合要求的证书和密钥。 假设实例集群拓扑如下: Name Host IP Services node1 172.16.10.11 DM-master1 node2 172.16.10.12 DM-master2 node3 172.16.10.13 DM-master3 node4 172.16.10.14 DM

  • 我试图建立一个安全的连接,我的应用程序使用jetty超文本传输协议服务器版本8.1.8. v20121106与自签名证书。 我正在使用以下命令生成自签名证书, > keytool-export-alias mykey-file server。cer-密钥库。jks-storepass密码 server.cer密钥存储truststore.jks密码 因此,总共生成3个文件(keystore.jks

  • 我四处寻找,但没有找到一个明确的例子。我想以编程方式(C#)创建一个自签名(自)信任的证书,执行以下步骤: 步骤1: 即时创建根CA证书并将其添加到“受信任的根证书颁发机构”文件夹中的证书存储中 我做到了(参见下面的代码-步骤1)。如何完成第2步?目标计算机是Windows XP/7。 我尝试了纯.NET方法和Bouncy Castle库。

  • 我在获取手机和Huawei GT2 Pro(HarmonyOS Watch)之间通信的Android应用程序的签名证书指纹时遇到了问题。我在华为开发者网站(https://developer.Huawei.com/consumer/en/doc/development/connectivity-guides/service-integratution-0000000000018585)上遵循Wea

  • 我正在尝试使用Bouncy Castle fips库生成一个签名的CSR,其中有一个存在于USB令牌中的私钥。 我正在使用PKCS10CertificationRequest对象生成一个签名的CSR,它期望ContentSigner对象作为输入,因此我通过实现方法1创建了自己的ContentSigner。getSignature()。2.getoutputstream()。3.getalgorit