github.com/MetalBlockchain/metalgo@v1.11.9/staking/parse.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package staking 5 6 import ( 7 "crypto" 8 "crypto/ecdsa" 9 "crypto/elliptic" 10 "crypto/rsa" 11 "encoding/asn1" 12 "errors" 13 "fmt" 14 "math/big" 15 16 "golang.org/x/crypto/cryptobyte" 17 18 "github.com/MetalBlockchain/metalgo/utils/units" 19 20 cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" 21 ) 22 23 const ( 24 MaxCertificateLen = 2 * units.KiB 25 26 allowedRSASmallModulusLen = 2048 27 allowedRSALargeModulusLen = 4096 28 allowedRSAPublicExponentValue = 65537 29 ) 30 31 var ( 32 ErrCertificateTooLarge = fmt.Errorf("staking: certificate length is greater than %d", MaxCertificateLen) 33 ErrMalformedCertificate = errors.New("staking: malformed certificate") 34 ErrMalformedTBSCertificate = errors.New("staking: malformed tbs certificate") 35 ErrMalformedVersion = errors.New("staking: malformed version") 36 ErrMalformedSerialNumber = errors.New("staking: malformed serial number") 37 ErrMalformedSignatureAlgorithmIdentifier = errors.New("staking: malformed signature algorithm identifier") 38 ErrMalformedIssuer = errors.New("staking: malformed issuer") 39 ErrMalformedValidity = errors.New("staking: malformed validity") 40 ErrMalformedSPKI = errors.New("staking: malformed spki") 41 ErrMalformedPublicKeyAlgorithmIdentifier = errors.New("staking: malformed public key algorithm identifier") 42 ErrMalformedSubjectPublicKey = errors.New("staking: malformed subject public key") 43 ErrMalformedOID = errors.New("staking: malformed oid") 44 ErrInvalidRSAPublicKey = errors.New("staking: invalid RSA public key") 45 ErrInvalidRSAModulus = errors.New("staking: invalid RSA modulus") 46 ErrInvalidRSAPublicExponent = errors.New("staking: invalid RSA public exponent") 47 ErrRSAModulusNotPositive = errors.New("staking: RSA modulus is not a positive number") 48 ErrUnsupportedRSAModulusBitLen = errors.New("staking: unsupported RSA modulus bitlen") 49 ErrRSAModulusIsEven = errors.New("staking: RSA modulus is an even number") 50 ErrUnsupportedRSAPublicExponent = errors.New("staking: unsupported RSA public exponent") 51 ErrFailedUnmarshallingEllipticCurvePoint = errors.New("staking: failed to unmarshal elliptic curve point") 52 ErrUnknownPublicKeyAlgorithm = errors.New("staking: unknown public key algorithm") 53 ) 54 55 // ParseCertificate parses a single certificate from the given ASN.1. 56 // 57 // This function does not validate that the certificate is valid to be used 58 // against normal TLS implementations. 59 // 60 // Ref: https://github.com/golang/go/blob/go1.19.12/src/crypto/x509/parser.go#L789-L968 61 func ParseCertificate(bytes []byte) (*Certificate, error) { 62 if len(bytes) > MaxCertificateLen { 63 return nil, ErrCertificateTooLarge 64 } 65 66 input := cryptobyte.String(bytes) 67 // Consume the length and tag bytes. 68 if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { 69 return nil, ErrMalformedCertificate 70 } 71 72 // Read the "to be signed" certificate into input. 73 if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { 74 return nil, ErrMalformedTBSCertificate 75 } 76 if !input.SkipOptionalASN1(cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { 77 return nil, ErrMalformedVersion 78 } 79 if !input.SkipASN1(cryptobyte_asn1.INTEGER) { 80 return nil, ErrMalformedSerialNumber 81 } 82 if !input.SkipASN1(cryptobyte_asn1.SEQUENCE) { 83 return nil, ErrMalformedSignatureAlgorithmIdentifier 84 } 85 if !input.SkipASN1(cryptobyte_asn1.SEQUENCE) { 86 return nil, ErrMalformedIssuer 87 } 88 if !input.SkipASN1(cryptobyte_asn1.SEQUENCE) { 89 return nil, ErrMalformedValidity 90 } 91 if !input.SkipASN1(cryptobyte_asn1.SEQUENCE) { 92 return nil, ErrMalformedIssuer 93 } 94 95 // Read the "subject public key info" into input. 96 if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { 97 return nil, ErrMalformedSPKI 98 } 99 100 // Read the public key algorithm identifier. 101 var pkAISeq cryptobyte.String 102 if !input.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { 103 return nil, ErrMalformedPublicKeyAlgorithmIdentifier 104 } 105 var pkAI asn1.ObjectIdentifier 106 if !pkAISeq.ReadASN1ObjectIdentifier(&pkAI) { 107 return nil, ErrMalformedOID 108 } 109 110 // Note: Unlike the x509 package, we require parsing the public key. 111 112 var spk asn1.BitString 113 if !input.ReadASN1BitString(&spk) { 114 return nil, ErrMalformedSubjectPublicKey 115 } 116 publicKey, err := parsePublicKey(pkAI, spk) 117 return &Certificate{ 118 Raw: bytes, 119 PublicKey: publicKey, 120 }, err 121 } 122 123 // Ref: https://github.com/golang/go/blob/go1.19.12/src/crypto/x509/parser.go#L215-L306 124 func parsePublicKey(oid asn1.ObjectIdentifier, publicKey asn1.BitString) (crypto.PublicKey, error) { 125 der := cryptobyte.String(publicKey.RightAlign()) 126 switch { 127 case oid.Equal(oidPublicKeyRSA): 128 pub := &rsa.PublicKey{N: new(big.Int)} 129 if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { 130 return nil, ErrInvalidRSAPublicKey 131 } 132 if !der.ReadASN1Integer(pub.N) { 133 return nil, ErrInvalidRSAModulus 134 } 135 if !der.ReadASN1Integer(&pub.E) { 136 return nil, ErrInvalidRSAPublicExponent 137 } 138 139 if pub.N.Sign() <= 0 { 140 return nil, ErrRSAModulusNotPositive 141 } 142 143 if bitLen := pub.N.BitLen(); bitLen != allowedRSALargeModulusLen && bitLen != allowedRSASmallModulusLen { 144 return nil, fmt.Errorf("%w: %d", ErrUnsupportedRSAModulusBitLen, bitLen) 145 } 146 if pub.N.Bit(0) == 0 { 147 return nil, ErrRSAModulusIsEven 148 } 149 if pub.E != allowedRSAPublicExponentValue { 150 return nil, fmt.Errorf("%w: %d", ErrUnsupportedRSAPublicExponent, pub.E) 151 } 152 return pub, nil 153 case oid.Equal(oidPublicKeyECDSA): 154 namedCurve := elliptic.P256() 155 x, y := elliptic.Unmarshal(namedCurve, der) 156 if x == nil { 157 return nil, ErrFailedUnmarshallingEllipticCurvePoint 158 } 159 return &ecdsa.PublicKey{ 160 Curve: namedCurve, 161 X: x, 162 Y: y, 163 }, nil 164 default: 165 return nil, ErrUnknownPublicKeyAlgorithm 166 } 167 }