25
25
package com .yubico .webauthn ;
26
26
27
27
import COSE .CoseException ;
28
- import COSE .OneKey ;
29
28
import com .google .common .primitives .Bytes ;
30
29
import com .upokecenter .cbor .CBORObject ;
31
30
import com .yubico .webauthn .data .ByteArray ;
46
45
47
46
final class WebAuthnCodecs {
48
47
48
+ private static final ByteArray EC_PUBLIC_KEY_OID =
49
+ new ByteArray (
50
+ new byte [] {
51
+ 0x2A , -122 , 0x48 , -50 , 0x3D , 0x02 , 0x01
52
+ }); // OID 1.2.840.10045.2.1 ecPublicKey (ANSI X9.62 public key type)
53
+ private static final ByteArray P256_CURVE_OID =
54
+ new ByteArray (
55
+ new byte [] {0x2A , -122 , 0x48 , -50 , 0x3D , 0x03 , 0x01 , 7 }); // OID 1.2.840.10045.3.1.7
56
+ private static final ByteArray P384_CURVE_OID =
57
+ new ByteArray (new byte [] {0x2B , -127 , 0x04 , 0 , 34 }); // OID 1.3.132.0.34
58
+ private static final ByteArray P512_CURVE_OID =
59
+ new ByteArray (new byte [] {0x2B , -127 , 0x04 , 0 , 35 }); // OID 1.3.132.0.35
60
+
49
61
private static final ByteArray ED25519_CURVE_OID =
50
62
new ByteArray (new byte [] {0x30 , 0x05 , 0x06 , 0x03 , 0x2B , 0x65 , 0x70 });
51
63
@@ -130,7 +142,7 @@ static PublicKey importCosePublicKey(ByteArray key)
130
142
// additional dependency to parse EdDSA keys via the OneKey constructor
131
143
return importCoseEdDsaPublicKey (cose );
132
144
case 2 :
133
- return importCoseP256PublicKey (cose );
145
+ return importCoseEcdsaPublicKey (cose );
134
146
case 3 :
135
147
// COSE-JAVA supports RSA in v1.1.0 but not in v1.0.0
136
148
return importCoseRsaPublicKey (cose );
@@ -148,8 +160,43 @@ private static PublicKey importCoseRsaPublicKey(CBORObject cose)
148
160
return KeyFactory .getInstance ("RSA" ).generatePublic (spec );
149
161
}
150
162
151
- private static ECPublicKey importCoseP256PublicKey (CBORObject cose ) throws CoseException {
152
- return (ECPublicKey ) new OneKey (cose ).AsPublicKey ();
163
+ private static PublicKey importCoseEcdsaPublicKey (CBORObject cose )
164
+ throws NoSuchAlgorithmException , InvalidKeySpecException {
165
+ final int crv = cose .get (CBORObject .FromObject (-1 )).AsInt32Value ();
166
+ final ByteArray x = new ByteArray (cose .get (CBORObject .FromObject (-2 )).GetByteString ());
167
+ final ByteArray y = new ByteArray (cose .get (CBORObject .FromObject (-3 )).GetByteString ());
168
+
169
+ final ByteArray curveOid ;
170
+ switch (crv ) {
171
+ case 1 :
172
+ curveOid = P256_CURVE_OID ;
173
+ break ;
174
+
175
+ case 2 :
176
+ curveOid = P384_CURVE_OID ;
177
+ break ;
178
+
179
+ case 3 :
180
+ curveOid = P512_CURVE_OID ;
181
+ break ;
182
+
183
+ default :
184
+ throw new IllegalArgumentException ("Unknown COSE EC2 curve: " + crv );
185
+ }
186
+
187
+ final ByteArray algId =
188
+ encodeDerSequence (encodeDerObjectId (EC_PUBLIC_KEY_OID ), encodeDerObjectId (curveOid ));
189
+
190
+ final ByteArray rawKey =
191
+ encodeDerBitStringWithZeroUnused (
192
+ new ByteArray (new byte [] {0x04 }) // Raw EC public key with x and y
193
+ .concat (x )
194
+ .concat (y ));
195
+
196
+ final ByteArray x509Key = encodeDerSequence (algId , rawKey );
197
+
198
+ KeyFactory kFact = KeyFactory .getInstance ("EC" );
199
+ return kFact .generatePublic (new X509EncodedKeySpec (x509Key .getBytes ()));
153
200
}
154
201
155
202
private static ByteArray encodeDerLength (final int length ) {
@@ -166,6 +213,10 @@ private static ByteArray encodeDerLength(final int length) {
166
213
}
167
214
}
168
215
216
+ private static ByteArray encodeDerObjectId (final ByteArray oid ) {
217
+ return new ByteArray (new byte [] {0x06 , (byte ) oid .size ()}).concat (oid );
218
+ }
219
+
169
220
private static ByteArray encodeDerBitStringWithZeroUnused (final ByteArray content ) {
170
221
return new ByteArray (new byte [] {0x03 })
171
222
.concat (encodeDerLength (1 + content .size ()))
0 commit comments