私には奇妙な要件があります。暗号システムにTBS証明書を渡す必要があります。署名システムに署名し、署名入りの証明書を作成するために証明書に組み込む必要がある署名の文字列を送り返します。証明書に署名を追加する
SO.COMのcom.ibm.security.x509.X509CertImplと様々なBouncyCastle投稿を見ると、その方法を見つけることができません。
質問:
これは可能ですか? そうなら、どうですか?
私には奇妙な要件があります。暗号システムにTBS証明書を渡す必要があります。署名システムに署名し、署名入りの証明書を作成するために証明書に組み込む必要がある署名の文字列を送り返します。証明書に署名を追加する
SO.COMのcom.ibm.security.x509.X509CertImplと様々なBouncyCastle投稿を見ると、その方法を見つけることができません。
質問:
これは可能ですか? そうなら、どうですか?
私はBouncyCastle X509v3CertificateBuilderクラス(pkix jar)のソースコードを参照して、ニーズに合わせて調整します。このクラスはV3TBSCertificateGeneratorを使用してTBSCertificateを生成します。これは、DERでエンコードできるASN.1オブジェクトです。次に、 "暗号システム"によって署名されたDERエンコーディングを取得することができます。次に、最終的なX.509証明書にTBS証明書と署名を組み込む方法については、X509v3CertificateBuilder.build()メソッドを参照してください。
私はこれを行う方法の一例をまとめました。このコードの大部分は、バウンシーキャスルのpkixやlwcryptoライブラリから盗まれましたが、バグはほぼ確実に私のものです。下に集中する最も重要な方法はgenerateCert
です。残りのコードは、テストを駆動するテストハーネスです。
コードは、bounycastle bcpkixとlwcrypto jarsだけを必要とするように具体的に書かれています。 lwcryptoの代わりにbcprov jarを使用した場合は、いくぶん短縮できます。
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.bc.BcX509v3CertificateBuilder;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import javax.security.auth.x500.X500Principal;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Date;
public class Main {
private static class TBSCertPlusSignature {
private final byte[] encodedTbsCert;
private final byte[] signature;
public TBSCertPlusSignature(byte[] encodedTbsCert, byte[] signature) {
this.encodedTbsCert = encodedTbsCert;
this.signature = signature;
}
public byte[] getEncodedTbsCert() {
return encodedTbsCert;
}
public byte[] getSignature() {
return signature;
}
}
private static TBSCertPlusSignature makeTestCert(KeyPair keyPair) throws Exception {
Date now = new Date();
Date nowPlus1Hour = new Date(now.getTime() + 1000 * 60 * 60 * 1L);
byte[] encodedName = new X500Principal("CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").getEncoded();
X500Name issuer = X500Name.getInstance(encodedName);
X500Name subject = issuer;
RSAPublicKey rsaPub = (RSAPublicKey) keyPair.getPublic();
RSAKeyParameters rsaPubParams = new RSAKeyParameters(false, rsaPub.getModulus(), rsaPub.getPublicExponent());
BcX509v3CertificateBuilder certBuilder = new BcX509v3CertificateBuilder(
issuer,
BigInteger.valueOf(100L),
now,
nowPlus1Hour,
subject,
rsaPubParams
);
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
RSAPrivateCrtKey rsaPriv = (RSAPrivateCrtKey) keyPair.getPrivate();
RSAPrivateCrtKeyParameters rsaPrivParams = new RSAPrivateCrtKeyParameters(
rsaPriv.getModulus(),
rsaPriv.getPublicExponent(),
rsaPriv.getPrivateExponent(),
rsaPriv.getPrimeP(),
rsaPriv.getPrimeQ(),
rsaPriv.getPrimeExponentP(),
rsaPriv.getPrimeExponentQ(),
rsaPriv.getCrtCoefficient()
);
ContentSigner contentSigner = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(rsaPrivParams);
final X509CertificateHolder x509CertificateHolder = certBuilder.build(contentSigner);
byte[] tbsCertDER = x509CertificateHolder.toASN1Structure().getTBSCertificate().getEncoded();
byte[] signature = x509CertificateHolder.getSignature();
return new TBSCertPlusSignature(tbsCertDER, signature);
}
private static X509Certificate generateCert(byte[] tbsCertEncoded, byte[] signature) throws Exception {
// Given the der encoded TBS cert and signature, create the corresponding X509 certificate
TBSCertificate tbsCert = TBSCertificate.getInstance(tbsCertEncoded);
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(tbsCert);
v.add(tbsCert.getSignature());
v.add(new DERBitString(signature));
DERSequence derSequence = new DERSequence(v);
ByteArrayInputStream baos = new ByteArrayInputStream(derSequence.getEncoded());
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(baos);
}
public static void main(String[] args) throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
TBSCertPlusSignature testData = makeTestCert(keyPair);
X509Certificate x509Cert = generateCert(testData.getEncodedTbsCert(), testData.getSignature());
// Verify the signature
x509Cert.verify(keyPair.getPublic());
// Print the cert
PublicKey publicKey = x509Cert.getPublicKey();
System.out.println(x509Cert);
}
}