@@ -18,6 +18,7 @@ import (
18
18
"bytes"
19
19
"crypto"
20
20
"crypto/ecdsa"
21
+ "crypto/ed25519"
21
22
"crypto/elliptic"
22
23
"crypto/rsa"
23
24
"crypto/x509"
@@ -250,10 +251,13 @@ type Algorithm int
250
251
// Algorithms supported by this package. Note that not all cards will support
251
252
// every algorithm.
252
253
//
254
+ // AlgorithmEd25519 is currently only implemented by SoloKeys.
255
+ //
253
256
// For algorithm discovery, see: https://github.com/ericchiang/piv-go/issues/1
254
257
const (
255
258
AlgorithmEC256 Algorithm = iota + 1
256
259
AlgorithmEC384
260
+ AlgorithmEd25519
257
261
AlgorithmRSA1024
258
262
AlgorithmRSA2048
259
263
)
@@ -304,6 +308,7 @@ var touchPolicyMap = map[TouchPolicy]byte{
304
308
var algorithmsMap = map [Algorithm ]byte {
305
309
AlgorithmEC256 : algECCP256 ,
306
310
AlgorithmEC384 : algECCP384 ,
311
+ AlgorithmEd25519 : algEd25519 ,
307
312
AlgorithmRSA1024 : algRSA1024 ,
308
313
AlgorithmRSA2048 : algRSA2048 ,
309
314
}
@@ -522,6 +527,12 @@ func ykGenerateKey(tx *scTx, slot Slot, o Key) (crypto.PublicKey, error) {
522
527
curve = elliptic .P256 ()
523
528
case AlgorithmEC384 :
524
529
curve = elliptic .P384 ()
530
+ case AlgorithmEd25519 :
531
+ pub , err := decodeEd25519Public (resp )
532
+ if err != nil {
533
+ return nil , fmt .Errorf ("decoding ed25519 public key: %v" , err )
534
+ }
535
+ return pub , nil
525
536
default :
526
537
return nil , fmt .Errorf ("unsupported algorithm" )
527
538
}
@@ -647,6 +658,8 @@ func (yk *YubiKey) PrivateKey(slot Slot, public crypto.PublicKey, auth KeyAuth)
647
658
switch pub := public .(type ) {
648
659
case * ecdsa.PublicKey :
649
660
return & keyECDSA {yk , slot , pub , auth , pp }, nil
661
+ case ed25519.PublicKey :
662
+ return & keyEd25519 {yk , slot , pub , auth , pp }, nil
650
663
case * rsa.PublicKey :
651
664
return & keyRSA {yk , slot , pub , auth , pp }, nil
652
665
default :
@@ -672,6 +685,24 @@ func (k *keyECDSA) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (
672
685
})
673
686
}
674
687
688
+ type keyEd25519 struct {
689
+ yk * YubiKey
690
+ slot Slot
691
+ pub ed25519.PublicKey
692
+ auth KeyAuth
693
+ pp PINPolicy
694
+ }
695
+
696
+ func (k * keyEd25519 ) Public () crypto.PublicKey {
697
+ return k .pub
698
+ }
699
+
700
+ func (k * keyEd25519 ) Sign (rand io.Reader , digest []byte , opts crypto.SignerOpts ) ([]byte , error ) {
701
+ return k .auth .do (k .yk , k .pp , func (tx * scTx ) ([]byte , error ) {
702
+ return skSignEd25519 (tx , k .slot , k .pub , digest )
703
+ })
704
+ }
705
+
675
706
type keyRSA struct {
676
707
yk * YubiKey
677
708
slot Slot
@@ -739,6 +770,34 @@ func ykSignECDSA(tx *scTx, slot Slot, pub *ecdsa.PublicKey, digest []byte) ([]by
739
770
return rs , nil
740
771
}
741
772
773
+ // This function only works on SoloKeys prototypes and other PIV devices that choose
774
+ // to implement Ed25519 signatures under alg 0x22.
775
+ func skSignEd25519 (tx * scTx , slot Slot , pub ed25519.PublicKey , digest []byte ) ([]byte , error ) {
776
+ // Adaptation of
777
+ // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=118
778
+ cmd := apdu {
779
+ instruction : insAuthenticate ,
780
+ param1 : algEd25519 ,
781
+ param2 : byte (slot .Key ),
782
+ data : marshalASN1 (0x7c ,
783
+ append ([]byte {0x82 , 0x00 },
784
+ marshalASN1 (0x81 , digest )... )),
785
+ }
786
+ resp , err := tx .Transmit (cmd )
787
+ if err != nil {
788
+ return nil , fmt .Errorf ("command failed: %w" , err )
789
+ }
790
+ sig , _ , err := unmarshalASN1 (resp , 1 , 0x1c ) // 0x7c
791
+ if err != nil {
792
+ return nil , fmt .Errorf ("unmarshal response: %v" , err )
793
+ }
794
+ rs , _ , err := unmarshalASN1 (sig , 2 , 0x02 ) // 0x82
795
+ if err != nil {
796
+ return nil , fmt .Errorf ("unmarshal response signature: %v" , err )
797
+ }
798
+ return rs , nil
799
+ }
800
+
742
801
func unmarshalASN1 (b []byte , class , tag int ) (obj , rest []byte , err error ) {
743
802
var v asn1.RawValue
744
803
rest , err = asn1 .Unmarshal (b , & v )
@@ -780,6 +839,23 @@ func decodeECPublic(b []byte, curve elliptic.Curve) (*ecdsa.PublicKey, error) {
780
839
return & ecdsa.PublicKey {Curve : curve , X : & x , Y : & y }, nil
781
840
}
782
841
842
+ func decodeEd25519Public (b []byte ) (ed25519.PublicKey , error ) {
843
+ // Adaptation of
844
+ // https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=95
845
+ r , _ , err := unmarshalASN1 (b , 1 , 0x49 )
846
+ if err != nil {
847
+ return nil , fmt .Errorf ("unmarshal response: %v" , err )
848
+ }
849
+ p , _ , err := unmarshalASN1 (r , 2 , 0x06 )
850
+ if err != nil {
851
+ return nil , fmt .Errorf ("unmarshal points: %v" , err )
852
+ }
853
+ if len (p ) != ed25519 .PublicKeySize {
854
+ return nil , fmt .Errorf ("unexpected points length: %d" , len (p ))
855
+ }
856
+ return ed25519 .PublicKey (p ), nil
857
+ }
858
+
783
859
func decodeRSAPublic (b []byte ) (* rsa.PublicKey , error ) {
784
860
// https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf#page=95
785
861
r , _ , err := unmarshalASN1 (b , 1 , 0x49 )
0 commit comments