11using System ;
22using System . Security . Cryptography ;
33using System . Security . Cryptography . X509Certificates ;
4-
54using Fido2NetLib . Cbor ;
6-
75using NSec . Cryptography ;
86
97namespace Fido2NetLib . Objects ;
@@ -13,6 +11,9 @@ public sealed class CredentialPublicKey
1311 internal readonly COSE . KeyType _type ;
1412 internal readonly COSE . Algorithm _alg ;
1513 internal readonly CborMap _cpk ;
14+ internal readonly ECDsa ? _ecdsa ;
15+ internal readonly RSA ? _rsa ;
16+ internal readonly NSec . Cryptography . PublicKey ? _eddsa ;
1617
1718 public CredentialPublicKey ( byte [ ] cpk )
1819 : this ( ( CborMap ) CborObject . Decode ( cpk ) ) { }
@@ -22,6 +23,25 @@ public CredentialPublicKey(CborMap cpk)
2223 _cpk = cpk ;
2324 _type = ( COSE . KeyType ) ( int ) cpk [ COSE . KeyCommonParameter . KeyType ] ;
2425 _alg = ( COSE . Algorithm ) ( int ) cpk [ COSE . KeyCommonParameter . Alg ] ;
26+ switch ( _type )
27+ {
28+ case COSE . KeyType . EC2 :
29+ {
30+ _ecdsa = CreateECDsa ( ) ;
31+ return ;
32+ }
33+ case COSE . KeyType . RSA :
34+ {
35+ _rsa = CreateRSA ( ) ;
36+ return ;
37+ }
38+ case COSE . KeyType . OKP :
39+ {
40+ _eddsa = CreateEdDSA ( ) ;
41+ return ;
42+ }
43+ }
44+ throw new InvalidOperationException ( $ "Missing or unknown kty { _type } ") ;
2545 }
2646
2747 public CredentialPublicKey ( ECDsa ecdsaPublicKey , COSE . Algorithm alg )
@@ -39,6 +59,7 @@ public CredentialPublicKey(ECDsa ecdsaPublicKey, COSE.Algorithm alg)
3959 { COSE . KeyTypeParameter . X , keyParams . Q . X ! } ,
4060 { COSE . KeyTypeParameter . Y , keyParams . Q . Y ! }
4161 } ;
62+ _ecdsa = CreateECDsa ( ) ;
4263 }
4364
4465 public CredentialPublicKey ( X509Certificate2 cert , COSE . Algorithm alg )
@@ -51,21 +72,36 @@ public CredentialPublicKey(X509Certificate2 cert, COSE.Algorithm alg)
5172 { COSE . KeyCommonParameter . KeyType , _type } ,
5273 { COSE . KeyCommonParameter . Alg , _alg }
5374 } ;
54-
55- if ( _type is COSE . KeyType . RSA )
56- {
57- var keyParams = cert . GetRSAPublicKey ( ) ! . ExportParameters ( false ) ;
58- _cpk . Add ( COSE . KeyTypeParameter . N , keyParams . Modulus ! ) ;
59- _cpk . Add ( COSE . KeyTypeParameter . E , keyParams . Exponent ! ) ;
60- }
61- else if ( _type is COSE . KeyType . EC2 )
75+ switch ( _type )
6276 {
63- var ecDsaPubKey = cert . GetECDsaPublicKey ( ) ! ;
64- var keyParams = ecDsaPubKey . ExportParameters ( false ) ;
65-
66- _cpk . Add ( COSE . KeyTypeParameter . Crv , keyParams . Curve . ToCoseCurve ( ) ) ;
67- _cpk . Add ( COSE . KeyTypeParameter . X , keyParams . Q . X ! ) ;
68- _cpk . Add ( COSE . KeyTypeParameter . Y , keyParams . Q . Y ! ) ;
77+ case COSE . KeyType . RSA :
78+ {
79+ var keyParams = cert . GetRSAPublicKey ( ) ! . ExportParameters ( false ) ;
80+ _cpk . Add ( COSE . KeyTypeParameter . N , keyParams . Modulus ! ) ;
81+ _cpk . Add ( COSE . KeyTypeParameter . E , keyParams . Exponent ! ) ;
82+ _rsa = CreateRSA ( ) ;
83+ break ;
84+ }
85+ case COSE . KeyType . EC2 :
86+ {
87+ var ecDsaPubKey = cert . GetECDsaPublicKey ( ) ! ;
88+ var keyParams = ecDsaPubKey . ExportParameters ( false ) ;
89+
90+ _cpk . Add ( COSE . KeyTypeParameter . Crv , keyParams . Curve . ToCoseCurve ( ) ) ;
91+ _cpk . Add ( COSE . KeyTypeParameter . X , keyParams . Q . X ! ) ;
92+ _cpk . Add ( COSE . KeyTypeParameter . Y , keyParams . Q . Y ! ) ;
93+ _ecdsa = CreateECDsa ( ) ;
94+ break ;
95+ }
96+ case COSE . KeyType . OKP :
97+ {
98+ _cpk . Add ( COSE . KeyTypeParameter . Crv , COSE . EllipticCurve . Ed25519 ) ;
99+ _cpk . Add ( COSE . KeyTypeParameter . X , cert . PublicKey . EncodedKeyValue . RawData ) ;
100+ _eddsa = CreateEdDSA ( ) ;
101+ break ;
102+ }
103+ default :
104+ throw new InvalidOperationException ( $ "Missing or unknown kty { _type } ") ;
69105 }
70106 }
71107
@@ -74,20 +110,14 @@ public bool Verify(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature)
74110 switch ( _type )
75111 {
76112 case COSE . KeyType . EC2 :
77- using ( ECDsa ecdsa = CreateECDsa ( ) )
78- {
79- var ecsig = CryptoUtils . SigFromEcDsaSig ( signature . ToArray ( ) , ecdsa . KeySize ) ;
80- return ecdsa . VerifyData ( data , ecsig , CryptoUtils . HashAlgFromCOSEAlg ( _alg ) ) ;
81- }
113+ var ecsig = CryptoUtils . SigFromEcDsaSig ( signature . ToArray ( ) , _ecdsa ! . KeySize ) ;
114+ return _ecdsa ! . VerifyData ( data , ecsig , CryptoUtils . HashAlgFromCOSEAlg ( _alg ) ) ;
82115
83116 case COSE . KeyType . RSA :
84- using ( RSA rsa = CreateRSA ( ) )
85- {
86- return rsa . VerifyData ( data , signature , CryptoUtils . HashAlgFromCOSEAlg ( _alg ) , Padding ) ;
87- }
117+ return _rsa ! . VerifyData ( data , signature , CryptoUtils . HashAlgFromCOSEAlg ( _alg ) , Padding ) ;
88118
89119 case COSE . KeyType . OKP :
90- return SignatureAlgorithm . Ed25519 . Verify ( EdDSAPublicKey , data , signature ) ;
120+ return SignatureAlgorithm . Ed25519 . Verify ( _eddsa ! , data , signature ) ;
91121 }
92122 throw new InvalidOperationException ( $ "Missing or unknown kty { _type } ") ;
93123 }
@@ -182,32 +212,29 @@ internal RSASignaturePadding Padding
182212 }
183213 }
184214
185- internal NSec . Cryptography . PublicKey EdDSAPublicKey
215+ internal NSec . Cryptography . PublicKey CreateEdDSA ( )
186216 {
187- get
217+ if ( _type != COSE . KeyType . OKP )
188218 {
189- if ( _type != COSE . KeyType . OKP )
190- {
191- throw new InvalidOperationException ( $ "Must be a OKP key. Was { _type } ") ;
192- }
219+ throw new InvalidOperationException ( $ "Must be a OKP key. Was { _type } ") ;
220+ }
193221
194- switch ( _alg ) // https://www.iana.org/assignments/cose/cose.xhtml#algorithms
195- {
196- case COSE . Algorithm . EdDSA :
197- var crv = ( COSE . EllipticCurve ) ( int ) _cpk [ COSE . KeyTypeParameter . Crv ] ;
198-
199- // https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
200- if ( crv is COSE . EllipticCurve . Ed25519 )
201- {
202- return NSec . Cryptography . PublicKey . Import ( SignatureAlgorithm . Ed25519 , ( byte [ ] ) _cpk [ COSE . KeyTypeParameter . X ] , KeyBlobFormat . RawPublicKey ) ;
203- }
204- else
205- {
206- throw new InvalidOperationException ( $ "Missing or unknown crv { crv } ") ;
207- }
208- default :
209- throw new InvalidOperationException ( $ "Missing or unknown alg { _alg } ") ;
210- }
222+ switch ( _alg ) // https://www.iana.org/assignments/cose/cose.xhtml#algorithms
223+ {
224+ case COSE . Algorithm . EdDSA :
225+ var crv = ( COSE . EllipticCurve ) ( int ) _cpk [ COSE . KeyTypeParameter . Crv ] ;
226+
227+ // https://www.iana.org/assignments/cose/cose.xhtml#elliptic-curves
228+ if ( crv is COSE . EllipticCurve . Ed25519 )
229+ {
230+ return NSec . Cryptography . PublicKey . Import ( SignatureAlgorithm . Ed25519 , ( byte [ ] ) _cpk [ COSE . KeyTypeParameter . X ] , KeyBlobFormat . RawPublicKey ) ;
231+ }
232+ else
233+ {
234+ throw new InvalidOperationException ( $ "Missing or unknown crv { crv } ") ;
235+ }
236+ default :
237+ throw new InvalidOperationException ( $ "Missing or unknown alg { _alg } ") ;
211238 }
212239 }
213240
0 commit comments