ed25519.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package derhelpers
  2. import (
  3. "crypto"
  4. "crypto/ed25519"
  5. "crypto/x509/pkix"
  6. "encoding/asn1"
  7. "errors"
  8. )
  9. var errEd25519WrongID = errors.New("incorrect object identifier")
  10. var errEd25519WrongKeyType = errors.New("incorrect key type")
  11. // ed25519OID is the OID for the Ed25519 signature scheme: see
  12. // https://datatracker.ietf.org/doc/draft-ietf-curdle-pkix-04.
  13. var ed25519OID = asn1.ObjectIdentifier{1, 3, 101, 112}
  14. // subjectPublicKeyInfo reflects the ASN.1 object defined in the X.509 standard.
  15. //
  16. // This is defined in crypto/x509 as "publicKeyInfo".
  17. type subjectPublicKeyInfo struct {
  18. Algorithm pkix.AlgorithmIdentifier
  19. PublicKey asn1.BitString
  20. }
  21. // MarshalEd25519PublicKey creates a DER-encoded SubjectPublicKeyInfo for an
  22. // ed25519 public key, as defined in
  23. // https://tools.ietf.org/html/draft-ietf-curdle-pkix-04. This is analogous to
  24. // MarshalPKIXPublicKey in crypto/x509, which doesn't currently support Ed25519.
  25. func MarshalEd25519PublicKey(pk crypto.PublicKey) ([]byte, error) {
  26. pub, ok := pk.(ed25519.PublicKey)
  27. if !ok {
  28. return nil, errEd25519WrongKeyType
  29. }
  30. spki := subjectPublicKeyInfo{
  31. Algorithm: pkix.AlgorithmIdentifier{
  32. Algorithm: ed25519OID,
  33. },
  34. PublicKey: asn1.BitString{
  35. BitLength: len(pub) * 8,
  36. Bytes: pub,
  37. },
  38. }
  39. return asn1.Marshal(spki)
  40. }
  41. // ParseEd25519PublicKey returns the Ed25519 public key encoded by the input.
  42. func ParseEd25519PublicKey(der []byte) (crypto.PublicKey, error) {
  43. var spki subjectPublicKeyInfo
  44. if rest, err := asn1.Unmarshal(der, &spki); err != nil {
  45. return nil, err
  46. } else if len(rest) > 0 {
  47. return nil, errors.New("SubjectPublicKeyInfo too long")
  48. }
  49. if !spki.Algorithm.Algorithm.Equal(ed25519OID) {
  50. return nil, errEd25519WrongID
  51. }
  52. if spki.PublicKey.BitLength != ed25519.PublicKeySize*8 {
  53. return nil, errors.New("SubjectPublicKeyInfo PublicKey length mismatch")
  54. }
  55. return ed25519.PublicKey(spki.PublicKey.Bytes), nil
  56. }
  57. // oneAsymmetricKey reflects the ASN.1 structure for storing private keys in
  58. // https://tools.ietf.org/html/draft-ietf-curdle-pkix-04, excluding the optional
  59. // fields, which we don't use here.
  60. //
  61. // This is identical to pkcs8 in crypto/x509.
  62. type oneAsymmetricKey struct {
  63. Version int
  64. Algorithm pkix.AlgorithmIdentifier
  65. PrivateKey []byte
  66. }
  67. // curvePrivateKey is the innter type of the PrivateKey field of
  68. // oneAsymmetricKey.
  69. type curvePrivateKey []byte
  70. // MarshalEd25519PrivateKey returns a DER encoding of the input private key as
  71. // specified in https://tools.ietf.org/html/draft-ietf-curdle-pkix-04.
  72. func MarshalEd25519PrivateKey(sk crypto.PrivateKey) ([]byte, error) {
  73. priv, ok := sk.(ed25519.PrivateKey)
  74. if !ok {
  75. return nil, errEd25519WrongKeyType
  76. }
  77. // Marshal the innter CurvePrivateKey.
  78. curvePrivateKey, err := asn1.Marshal(priv.Seed())
  79. if err != nil {
  80. return nil, err
  81. }
  82. // Marshal the OneAsymmetricKey.
  83. asym := oneAsymmetricKey{
  84. Version: 0,
  85. Algorithm: pkix.AlgorithmIdentifier{
  86. Algorithm: ed25519OID,
  87. },
  88. PrivateKey: curvePrivateKey,
  89. }
  90. return asn1.Marshal(asym)
  91. }
  92. // ParseEd25519PrivateKey returns the Ed25519 private key encoded by the input.
  93. func ParseEd25519PrivateKey(der []byte) (crypto.PrivateKey, error) {
  94. asym := new(oneAsymmetricKey)
  95. if rest, err := asn1.Unmarshal(der, asym); err != nil {
  96. return nil, err
  97. } else if len(rest) > 0 {
  98. return nil, errors.New("OneAsymmetricKey too long")
  99. }
  100. // Check that the key type is correct.
  101. if !asym.Algorithm.Algorithm.Equal(ed25519OID) {
  102. return nil, errEd25519WrongID
  103. }
  104. // Unmarshal the inner CurvePrivateKey.
  105. seed := new(curvePrivateKey)
  106. if rest, err := asn1.Unmarshal(asym.PrivateKey, seed); err != nil {
  107. return nil, err
  108. } else if len(rest) > 0 {
  109. return nil, errors.New("CurvePrivateKey too long")
  110. }
  111. return ed25519.NewKeyFromSeed(*seed), nil
  112. }