32
32
33
33
import java .security .GeneralSecurityException ;
34
34
35
- import org .bouncycastle .asn1 .ASN1Boolean ;
36
- import org .bouncycastle .asn1 .ASN1Encodable ;
37
- import org .bouncycastle .asn1 .ASN1EncodableVector ;
38
- import org .bouncycastle .asn1 .ASN1Encoding ;
39
- import org .bouncycastle .asn1 .ASN1Integer ;
40
- import org .bouncycastle .asn1 .ASN1ObjectIdentifier ;
41
- import org .bouncycastle .asn1 .DERBitString ;
42
- import org .bouncycastle .asn1 .DEROctetString ;
43
- import org .bouncycastle .asn1 .DLSequence ;
35
+ import org .bouncycastle .asn1 .*;
36
+ import org .bouncycastle .asn1 .x500 .X500Name ;
44
37
import org .bouncycastle .asn1 .x509 .GeneralName ;
45
38
import org .bouncycastle .asn1 .x509 .GeneralNames ;
46
39
@@ -187,28 +180,28 @@ public IRubyObject create_ext(final ThreadContext context, final IRubyObject[] a
187
180
final ASN1Encodable value ;
188
181
try {
189
182
final String id = objectId .getId ();
190
- if (id .equals ("2.5.29.14" )) { //subjectKeyIdentifier
183
+ if (id .equals ("2.5.29.14" )) { // subjectKeyIdentifier
191
184
value = new DEROctetString (parseSubjectKeyIdentifier (context , oid , valuex ));
192
185
}
193
- else if (id .equals ("2.5.29.35" )) { //authorityKeyIdentifier
186
+ else if (id .equals ("2.5.29.35" )) { // authorityKeyIdentifier
194
187
value = parseAuthorityKeyIdentifier (context , valuex );
195
188
}
196
- else if (id .equals ("2.5.29.17" )) { //subjectAltName
189
+ else if (id .equals ("2.5.29.17" )) { // subjectAltName
197
190
value = parseSubjectAltName (valuex );
198
191
}
199
- else if (id .equals ("2.5.29.18" )) { //issuerAltName
192
+ else if (id .equals ("2.5.29.18" )) { // issuerAltName
200
193
value = parseIssuerAltName (context , valuex );
201
194
}
202
- else if (id .equals ("2.5.29.19" )) { //basicConstraints
195
+ else if (id .equals ("2.5.29.19" )) { // basicConstraints
203
196
value = parseBasicConstrains (valuex );
204
197
}
205
- else if (id .equals ("2.5.29.15" )) { //keyUsage
198
+ else if (id .equals ("2.5.29.15" )) { // keyUsage
206
199
value = parseKeyUsage (oid , valuex );
207
200
}
208
- else if (id .equals ("2.16.840.1.113730.1.1" )) { //nsCertType
201
+ else if (id .equals ("2.16.840.1.113730.1.1" )) { // nsCertType
209
202
value = parseNsCertType (oid , valuex );
210
203
}
211
- else if (id .equals ("2.5.29.37" )) { //extendedKeyUsage
204
+ else if (id .equals ("2.5.29.37" )) { // extendedKeyUsage
212
205
value = parseExtendedKeyUsage (valuex );
213
206
}
214
207
else {
@@ -404,19 +397,31 @@ private static DLSequence parseBasicConstrains(final String valuex) {
404
397
return new DLSequence (vec );
405
398
}
406
399
407
- private DLSequence parseAuthorityKeyIdentifier (final ThreadContext context , final String valuex ) {
400
+ private ASN1Sequence parseAuthorityKeyIdentifier (final ThreadContext context , final String valuex ) {
408
401
final ASN1EncodableVector vec = new ASN1EncodableVector ();
409
- if ( valuex .startsWith ("keyid:always" ) ) {
410
- vec .add (new DEROctetString (derDigest (context )));
411
- } else if ( valuex .startsWith ("keyid" ) ) {
412
- vec .add (new DEROctetString (derDigest (context )));
402
+
403
+ for ( String value : valuex .split ("," ) ) { // e.g. "keyid:always,issuer:always"
404
+ if ( value .startsWith ("keyid:" ) ) { // keyid:always
405
+ ASN1Encodable publicKeyIdentifier = new DEROctetString (publicKeyIdentifier (context ));
406
+ vec .add (new DERTaggedObject (false , 0 , publicKeyIdentifier ));
407
+ }
408
+ else if ( value .startsWith ("issuer:" ) ) { // issuer:always
409
+ GeneralName issuerName = new GeneralName (authorityCertIssuer (context ));
410
+ vec .add (new DERTaggedObject (false , 1 , new GeneralNames (issuerName )));
411
+
412
+ BigInteger issuerSerial = getIssuerSerialNumber (context );
413
+ if ( issuerSerial != null ) {
414
+ vec .add (new DERTaggedObject (false , 2 , new ASN1Integer (issuerSerial )));
415
+ }
416
+ }
413
417
}
414
- return new DLSequence (vec );
418
+
419
+ return new DERSequence (vec );
415
420
}
416
421
417
- private byte [] derDigest (final ThreadContext context ) {
422
+ private byte [] publicKeyIdentifier (final ThreadContext context ) {
418
423
final Ruby runtime = context .runtime ;
419
- IRubyObject pkey = getInstanceVariable ( "@issuer_certificate" ). callMethod ( context , "public_key" );
424
+ IRubyObject pkey = getPublicKey ( context );
420
425
IRubyObject der ;
421
426
if (pkey instanceof PKeyRSA ) {
422
427
der = pkey .callMethod (context , "to_der" );
@@ -427,6 +432,39 @@ private byte[] derDigest(final ThreadContext context) {
427
432
return getSHA1Digest (runtime , der .asString ().getBytes ());
428
433
}
429
434
435
+ private IRubyObject getPublicKey (final ThreadContext context ) {
436
+ IRubyObject issuer_cert = getInstanceVariable ("@issuer_certificate" );
437
+ if ( issuer_cert instanceof X509Cert ) {
438
+ return ((X509Cert ) issuer_cert ).public_key (context );
439
+ }
440
+ return issuer_cert .callMethod (context , "public_key" );
441
+ }
442
+
443
+ private X500Name authorityCertIssuer (final ThreadContext context ) {
444
+ IRubyObject issuer = getIssuer (context );
445
+ if ( issuer instanceof X509Name ) {
446
+ return ((X509Name ) issuer ).getX500Name ();
447
+ }
448
+ throw new UnsupportedOperationException ();
449
+ }
450
+
451
+ private IRubyObject getIssuer (final ThreadContext context ) {
452
+ IRubyObject issuer_cert = getInstanceVariable ("@issuer_certificate" );
453
+ if ( issuer_cert instanceof X509Cert ) {
454
+ return ((X509Cert ) issuer_cert ).getIssuer ();
455
+ }
456
+ return issuer_cert .callMethod (context , "issuer" );
457
+ }
458
+
459
+ private BigInteger getIssuerSerialNumber (final ThreadContext context ) {
460
+ IRubyObject issuer_cert = getInstanceVariable ("@issuer_certificate" );
461
+ if ( issuer_cert instanceof X509Cert ) {
462
+ return ((X509Cert ) issuer_cert ).getSerial ();
463
+ }
464
+ IRubyObject serial = issuer_cert .callMethod (context , "serial" );
465
+ return serial .isNil () ? null : ((BN ) serial ).getValue ();
466
+ }
467
+
430
468
private static byte [] getSHA1Digest (Ruby runtime , byte [] bytes ) {
431
469
try {
432
470
return SecurityHelper .getMessageDigest ("SHA-1" ).digest (bytes );
@@ -507,7 +545,7 @@ private static ASN1Encodable parseSubjectAltName(final String valuex) throws IOE
507
545
508
546
private DEROctetString parseSubjectKeyIdentifier (final ThreadContext context , final String oid , final String valuex ) {
509
547
if ( "hash" .equalsIgnoreCase (valuex ) ) {
510
- return new DEROctetString (derDigest (context ));
548
+ return new DEROctetString (publicKeyIdentifier (context ));
511
549
}
512
550
if ( valuex .length () == 20 || ! isHex (valuex ) ) {
513
551
return new DEROctetString (ByteList .plain (valuex ));
0 commit comments