31
31
import java .io .IOException ;
32
32
import java .io .InputStream ;
33
33
import java .io .PrintStream ;
34
- import java .lang .reflect .InvocationTargetException ;
35
- import java .lang .reflect .Method ;
36
34
import java .math .BigInteger ;
35
+ import java .nio .charset .StandardCharsets ;
37
36
import java .text .ParseException ;
38
37
import java .util .Date ;
39
38
import java .util .Enumeration ;
@@ -548,12 +547,12 @@ private static Map<ASN1ObjectIdentifier, String> getSymLookup(final Ruby runtime
548
547
{ "NUMERICSTRING" , org .bouncycastle .asn1 .DERNumericString .class , "NumericString" },
549
548
{ "PRINTABLESTRING" , org .bouncycastle .asn1 .DERPrintableString .class , "PrintableString" },
550
549
{ "T61STRING" , org .bouncycastle .asn1 .DERT61String .class , "T61String" },
551
- { "VIDEOTEXSTRING" , null , "VideotexString" },
550
+ { "VIDEOTEXSTRING" , org . bouncycastle . asn1 . DERVideotexString . class , "VideotexString" },
552
551
{ "IA5STRING" , org .bouncycastle .asn1 .DERIA5String .class , "IA5String" },
553
552
{ "UTCTIME" , org .bouncycastle .asn1 .DERUTCTime .class , "UTCTime" },
554
553
{ "GENERALIZEDTIME" , org .bouncycastle .asn1 .DERGeneralizedTime .class , "GeneralizedTime" },
555
- { "GRAPHICSTRING" , null , "GraphicString" },
556
- { "ISO64STRING" , null , "ISO64String" },
554
+ { "GRAPHICSTRING" , org . bouncycastle . asn1 . DERGraphicString . class , "GraphicString" },
555
+ { "ISO64STRING" , org . bouncycastle . asn1 . DERVisibleString . class , "ISO64String" },
557
556
{ "GENERALSTRING" , org .bouncycastle .asn1 .DERGeneralString .class , "GeneralString" },
558
557
// OpenSSL::ASN1::UNIVERSALSTRING (28) :
559
558
{ "UNIVERSALSTRING" , org .bouncycastle .asn1 .DERUniversalString .class , "UniversalString" },
@@ -662,25 +661,6 @@ static Class<? extends ASN1Encodable> typeClassSafe(final int typeId) {
662
661
return typeClass (typeId );
663
662
}
664
663
665
- static ASN1Encodable typeInstance (Class <? extends ASN1Encodable > type , Object value )
666
- throws NoSuchMethodException , IllegalAccessException , InvocationTargetException {
667
- Method getInstance = null ;
668
- try {
669
- getInstance = type .getMethod ("getInstance" , Object .class );
670
- }
671
- catch (NoSuchMethodException e ) {
672
- Class superType = type .getSuperclass ();
673
- try {
674
- if ( superType != Object .class ) {
675
- getInstance = type .getSuperclass ().getMethod ("getInstance" , Object .class );
676
- }
677
- }
678
- catch (NoSuchMethodException e2 ) { }
679
- if ( getInstance == null ) throw e ;
680
- }
681
- return (ASN1Encodable ) getInstance .invoke (null , value );
682
- }
683
-
684
664
public static void createASN1 (final Ruby runtime , final RubyModule OpenSSL , final RubyClass OpenSSLError ) {
685
665
final RubyModule ASN1 = OpenSSL .defineModuleUnder ("ASN1" );
686
666
ASN1 .defineClassUnder ("ASN1Error" , OpenSSLError , OpenSSLError .getAllocator ());
@@ -976,7 +956,22 @@ static IRubyObject decodeObject(final ThreadContext context,
976
956
final ByteList bytes ;
977
957
if ( obj instanceof ASN1UTF8String ) {
978
958
if ( type == null ) type = "UTF8String" ;
979
- bytes = new ByteList (((ASN1UTF8String ) obj ).getString ().getBytes ("UTF-8" ), false );
959
+ bytes = new ByteList (((ASN1UTF8String ) obj ).getString ().getBytes (StandardCharsets .UTF_8 ), false );
960
+ }
961
+ else if ( obj instanceof ASN1UniversalString ) {
962
+ if ( type == null ) type = "UniversalString" ;
963
+ bytes = new ByteList (((ASN1UniversalString ) obj ).getOctets (), false );
964
+ }
965
+ else if ( obj instanceof ASN1BMPString ) {
966
+ if ( type == null ) type = "BMPString" ;
967
+ final String val = ((ASN1BMPString ) obj ).getString ();
968
+ final byte [] valBytes = new byte [val .length () * 2 ];
969
+ for (int i = 0 ; i < val .length (); i ++) {
970
+ char c = val .charAt (i );
971
+ valBytes [i * 2 ] = (byte ) ((c >> 8 ) & 0xff );
972
+ valBytes [i * 2 + 1 ] = (byte ) (c & 0xff );
973
+ }
974
+ bytes = new ByteList (valBytes , false );
980
975
}
981
976
else {
982
977
if ( type == null ) {
@@ -995,14 +990,16 @@ else if ( obj instanceof ASN1T61String ) {
995
990
else if ( obj instanceof ASN1GeneralString ) {
996
991
type = "GeneralString" ;
997
992
}
998
- else if ( obj instanceof ASN1UniversalString ) {
999
- type = "UniversalString " ;
993
+ else if ( obj instanceof ASN1VideotexString ) {
994
+ type = "VideotexString " ;
1000
995
}
1001
- else if ( obj instanceof ASN1BMPString ) {
1002
- type = "BMPString" ;
996
+ else if ( obj instanceof ASN1VisibleString ) {
997
+ type = "ISO64String" ;
998
+ }
999
+ else if ( obj instanceof ASN1GraphicString ) {
1000
+ type = "GraphicString" ;
1003
1001
}
1004
1002
else {
1005
- // NOTE "VideotexString", "GraphicString", "ISO64String" not-handled in BC !
1006
1003
throw new IllegalArgumentException ("could not handle ASN1 string type: " + obj + " (" + obj .getClass ().getName () + ")" );
1007
1004
}
1008
1005
}
@@ -1652,38 +1649,50 @@ ASN1Encodable toASN1(final ThreadContext context) {
1652
1649
return new DERUTF8String ( val .asString ().toString () );
1653
1650
}
1654
1651
if ( type == DERBMPString .class ) {
1655
- return new DERBMPString ( val .asString ().toString () );
1652
+ return new DERBMPString (new String ( toBMPChars ( val .asString ().getByteList ())) );
1656
1653
}
1657
1654
if ( type == DERUniversalString .class ) {
1658
1655
return new DERUniversalString ( val .asString ().getBytes () );
1659
1656
}
1660
1657
1661
1658
if ( type == DERGeneralString .class ) {
1662
- return ASN1GeneralString . getInstance ( val .asString ().getBytes () );
1659
+ return new DERGeneralString ( val .asString ().toString () );
1663
1660
}
1664
1661
if ( type == DERVisibleString .class ) {
1665
- return ASN1VisibleString . getInstance ( val .asString ().getBytes () );
1662
+ return new DERVisibleString ( val .asString ().toString () );
1666
1663
}
1667
1664
if ( type == DERNumericString .class ) {
1668
- return ASN1NumericString . getInstance ( val .asString ().getBytes () );
1665
+ return new DERNumericString ( val .asString ().toString () );
1669
1666
}
1670
-
1671
- if ( val instanceof RubyString ) {
1672
- try {
1673
- return typeInstance (type , ( (RubyString ) val ).getBytes ());
1674
- }
1675
- catch (Exception e ) { // TODO exception handling
1676
- debugStackTrace (context .runtime , e );
1677
- throw Utils .newError (context .runtime , context .runtime .getRuntimeError (), e );
1678
- }
1667
+ if ( type == DERPrintableString .class ) {
1668
+ return new DERPrintableString ( val .asString ().toString () );
1669
+ }
1670
+ if ( type == DERT61String .class ) {
1671
+ return new DERT61String ( val .asString ().toString () );
1672
+ }
1673
+ if ( type == DERVideotexString .class ) {
1674
+ return new DERVideotexString ( val .asString ().getBytes () );
1675
+ }
1676
+ if ( type == DERGraphicString .class ) {
1677
+ return new DERGraphicString ( val .asString ().getBytes () );
1679
1678
}
1680
1679
1681
- // TODO throw an exception here too?
1682
- if ( isDebug (context .runtime ) ) {
1680
+ if (isDebug (context .runtime )) {
1683
1681
debug (this + " toASN1() could not handle class " + getMetaClass () + " and value " + val .inspect () + " (" + val .getClass ().getName () + ")" );
1684
1682
}
1685
- warn (context , "WARNING: unimplemented method called: OpenSSL::ASN1Data#toASN1 (" + type + ")" );
1686
- return null ;
1683
+ throw context .runtime .newNotImplementedError ("unimplemented method called: OpenSSL::ASN1Data#toASN1 (" + type + ")" );
1684
+ }
1685
+
1686
+ private static char [] toBMPChars (final ByteList string ) {
1687
+ assert string .length () % 2 == 0 ;
1688
+
1689
+ final int len = string .length () / 2 ;
1690
+ final char [] chars = new char [len ];
1691
+ for (int i = 0 ; i < len ; i ++) {
1692
+ int si = i * 2 ;
1693
+ chars [i ] = (char )((string .get (si ) << 8 ) | (string .get (si + 1 ) & 0xff ));
1694
+ }
1695
+ return chars ;
1687
1696
}
1688
1697
1689
1698
private static BigInteger bigIntegerValue (final IRubyObject val ) {
0 commit comments