|
32 | 32 | import java.io.StringWriter;
|
33 | 33 | import java.math.BigInteger;
|
34 | 34 |
|
35 |
| -import java.security.GeneralSecurityException; |
36 | 35 | import java.security.InvalidKeyException;
|
37 | 36 | import java.security.NoSuchAlgorithmException;
|
38 | 37 | import java.security.NoSuchProviderException;
|
|
60 | 59 | import org.bouncycastle.asn1.x509.GeneralName;
|
61 | 60 | import org.bouncycastle.asn1.x509.GeneralNames;
|
62 | 61 |
|
| 62 | +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; |
| 63 | +import org.bouncycastle.cert.X509CertificateHolder; |
| 64 | +import org.bouncycastle.cert.X509v3CertificateBuilder; |
| 65 | +import org.bouncycastle.operator.ContentSigner; |
| 66 | +import org.bouncycastle.operator.OperatorCreationException; |
| 67 | +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; |
63 | 68 | import org.joda.time.DateTime;
|
64 | 69 | import org.jruby.Ruby;
|
65 | 70 | import org.jruby.RubyArray;
|
@@ -593,60 +598,70 @@ else if (digest instanceof RubyString) {
|
593 | 598 | throw newCertificateError(runtime, "signature_algorithm not supported");
|
594 | 599 | }
|
595 | 600 |
|
596 |
| - org.bouncycastle.x509.X509V3CertificateGenerator builder = getCertificateBuilder(); |
597 |
| - |
| 601 | + final X509v3CertificateBuilder builder = newCertificateBuilder(); |
598 | 602 | for ( X509Extension ext : uniqueExtensions() ) {
|
599 | 603 | try {
|
600 | 604 | final byte[] bytes = ext.getRealValueEncoded();
|
601 |
| - builder.addExtension(ext.getRealObjectID().getId(), ext.isRealCritical(), bytes); |
| 605 | + builder.addExtension(ext.getRealObjectID(), ext.isRealCritical(), bytes); |
602 | 606 | }
|
603 |
| - catch (IOException ioe) { |
604 |
| - throw runtime.newIOErrorFromException(ioe); |
| 607 | + catch (IOException e) { |
| 608 | + throw newCertificateError(runtime, "invalid extension (" + e.getMessage() + ")", e); |
605 | 609 | }
|
606 | 610 | }
|
607 | 611 |
|
608 |
| - builder.setSignatureAlgorithm(digAlg + "WITH" + keyAlg); // "SHA1WITHRSA" |
609 |
| - |
| 612 | + final X509CertificateHolder certHolder; |
610 | 613 | try {
|
611 |
| - cert = builder.generate( ((PKey) key).getPrivateKey() ); |
612 |
| - } |
613 |
| - catch (GeneralSecurityException e) { |
614 |
| - throw newCertificateError(runtime, e); |
615 |
| - } |
616 |
| - catch (IllegalStateException e) { |
| 614 | + ContentSigner signer = |
| 615 | + new JcaContentSignerBuilder(digAlg + "WITH" + keyAlg). |
| 616 | + build(((PKey) key).getPrivateKey()); |
| 617 | + certHolder = builder.build(signer); |
| 618 | + } catch (OperatorCreationException e) { |
| 619 | + Exception cause = (Exception) e.getCause(); // GeneralSecurityException |
| 620 | + if (cause == null) cause = e; |
| 621 | + throw newCertificateError(runtime, "cannot create signer: " + cause.getMessage(), cause); |
| 622 | + } catch (IllegalStateException e) { |
617 | 623 | // e.g. "not all mandatory fields set in V3 TBScertificate generator"
|
618 | 624 | throw newCertificateError(runtime, "could not generate certificate", e);
|
| 625 | + } catch (RuntimeException e) { |
| 626 | + throw newCertificateError(runtime, e); |
619 | 627 | }
|
620 | 628 |
|
621 |
| - if (cert == null) throw newCertificateError(runtime, (String) null); |
| 629 | + try { |
| 630 | + this.cert = (X509Certificate) |
| 631 | + SecurityHelper.getCertificateFactory("X.509"). |
| 632 | + generateCertificate(new ByteArrayInputStream(certHolder.getEncoded())); |
| 633 | + } catch (IOException|CertificateException e) { |
| 634 | + throw newCertificateError(runtime, "could not re-generate certificate", e); |
| 635 | + } |
622 | 636 |
|
623 |
| - String name = ASN1Registry.o2a(cert.getSigAlgOID()); |
| 637 | + String name = ASN1Registry.o2a(certHolder.getSignatureAlgorithm().getAlgorithm()); |
624 | 638 | if ( name == null ) name = cert.getSigAlgOID();
|
625 | 639 | this.sig_alg = runtime.newString(name);
|
626 | 640 | this.changed = false;
|
627 | 641 | return this;
|
628 | 642 | }
|
629 | 643 |
|
630 |
| - private org.bouncycastle.x509.X509V3CertificateGenerator getCertificateBuilder() { |
631 |
| - org.bouncycastle.x509.X509V3CertificateGenerator generator = |
632 |
| - new org.bouncycastle.x509.X509V3CertificateGenerator(); |
633 |
| - if ( serial.equals(BigInteger.ZERO) ) { // NOTE: diversion from MRI (OpenSSL allows not setting serial) |
634 |
| - throw newCertificateError(getRuntime(), "Certificate#serial needs to be set (to > 0)"); |
635 |
| - } |
636 |
| - generator.setSerialNumber( serial.abs() ); |
637 |
| - |
638 |
| - if ( subject != null ) generator.setSubjectDN( ((X509Name) subject).getRealName() ); |
639 |
| - if ( issuer != null ) generator.setIssuerDN( ((X509Name) issuer).getRealName() ); |
| 644 | + private X509v3CertificateBuilder newCertificateBuilder() { |
| 645 | + //if ( serial.equals(BigInteger.ZERO) ) { // NOTE: diversion from MRI (OpenSSL allows not setting serial) |
| 646 | + // throw newCertificateError(getRuntime(), "Certificate#serial needs to be set (to > 0)"); |
| 647 | + //} |
640 | 648 |
|
641 |
| - generator.setNotBefore( not_before.getJavaDate() ); |
642 |
| - generator.setNotAfter( not_after.getJavaDate() ); |
643 |
| - generator.setPublicKey( getPublicKey() ); |
| 649 | + SubjectPublicKeyInfo publicKeyInfo; |
| 650 | + try { |
| 651 | + publicKeyInfo = SubjectPublicKeyInfo.getInstance(public_key.getPublicKey().getEncoded()); |
| 652 | + } catch (Exception e) { |
| 653 | + throw newCertificateError(getRuntime(), "invalid public key data", e); |
| 654 | + } |
644 | 655 |
|
645 |
| - return generator; |
| 656 | + return new X509v3CertificateBuilder( |
| 657 | + issuer == null ? null : ((X509Name) issuer).getX500Name(), |
| 658 | + serial.abs(), |
| 659 | + not_before.getJavaDate(), not_after.getJavaDate(), |
| 660 | + subject == null ? null : ((X509Name) subject).getX500Name(), |
| 661 | + publicKeyInfo |
| 662 | + ); |
646 | 663 | }
|
647 | 664 |
|
648 |
| - //private transient org.bouncycastle.x509.X509V3CertificateGenerator generator; |
649 |
| - |
650 | 665 | @JRubyMethod
|
651 | 666 | public RubyBoolean verify(final IRubyObject key) {
|
652 | 667 | final Ruby runtime = getRuntime();
|
|
0 commit comments