|
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