this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

crypto: remove panics by creating types earlier as needed

+44 -54
+1 -1
atproto/crypto/keys_test.go
··· 25 25 privP256Bytes := privP256.Bytes() 26 26 privP256FromBytes, err := ParsePrivateBytesP256(privP256Bytes) 27 27 assert.NoError(err) 28 - assert.Equal(privP256, privP256FromBytes) 28 + assert.True(privP256.Equal(privP256FromBytes)) 29 29 30 30 // private key generation and byte serialization (K-256) 31 31 privK256, err := GeneratePrivateKeyK256()
+41 -51
atproto/crypto/p256.go
··· 8 8 "crypto/sha256" 9 9 "crypto/x509" 10 10 "fmt" 11 - "log" 12 11 "math/big" 13 12 14 13 "github.com/mr-tron/base58" ··· 17 16 // Implements the [PrivateKeyExportable] and [PrivateKey] interfaces for the NIST P-256 / secp256r1 / ES256 cryptographic curve. 18 17 // Secret key material is naively stored in memory. 19 18 type PrivateKeyP256 struct { 20 - privP256 *ecdsa.PrivateKey 19 + privP256 ecdsa.PrivateKey 20 + privP256ecdh *ecdh.PrivateKey 21 21 } 22 22 23 23 // Implements the [PublicKey] interface for the NIST P-256 / secp256r1 / ES256 cryptographic curve. 24 24 type PublicKeyP256 struct { 25 - pubP256 *ecdsa.PublicKey 25 + pubP256 ecdsa.PublicKey 26 + pubP256ecdh ecdh.PublicKey 26 27 } 27 28 28 29 var _ PrivateKey = (*PrivateKeyP256)(nil) ··· 31 32 32 33 // Creates a secure new cryptographic key from scratch. 33 34 func GeneratePrivateKeyP256() (*PrivateKeyP256, error) { 34 - key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 35 + skECDSA, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 35 36 if err != nil { 36 37 return nil, fmt.Errorf("P-256/secp256r1 key generation failed: %w", err) 37 38 } 38 - priv := PrivateKeyP256{privP256: key} 39 - err = priv.ensureBytes() 39 + skECDH, err := skECDSA.ECDH() 40 40 if err != nil { 41 - return nil, err 41 + return nil, fmt.Errorf("unexpected internal error converting P-256 key from ecdsa to ecdh: %w", err) 42 42 } 43 - return &priv, nil 43 + return &PrivateKeyP256{privP256: *skECDSA, privP256ecdh: skECDH}, nil 44 44 } 45 45 46 46 // Loads a [PrivateKeyP256] from raw bytes, as exported by the PrivateKeyP256.Bytes method. ··· 49 49 func ParsePrivateBytesP256(data []byte) (*PrivateKeyP256, error) { 50 50 // elaborately parse as an ecdh.PrivateKey, then get from that to ecdsa.PrivateKey by encoding/decoding using x509 PKCS8 encoding. 51 51 // Note that the 'data' bytes format is *not* x509 PKCS8! 52 - skEcdh, err := ecdh.P256().NewPrivateKey(data) 52 + skECDH, err := ecdh.P256().NewPrivateKey(data) 53 53 if err != nil { 54 54 return nil, fmt.Errorf("invalid P-256/secp256r1 private key: %w", err) 55 55 } 56 - enc, err := x509.MarshalPKCS8PrivateKey(skEcdh) 56 + enc, err := x509.MarshalPKCS8PrivateKey(skECDH) 57 57 if err != nil { 58 58 return nil, fmt.Errorf("invalid P-256/secp256r1 private key: %w", err) 59 59 } ··· 63 63 } 64 64 skECDSA, ok := sk.(*ecdsa.PrivateKey) 65 65 if !ok { 66 - return nil, fmt.Errorf("expected ECDSA privatekey from internal encoding") 67 - } 68 - priv := PrivateKeyP256{privP256: skECDSA} 69 - err = priv.ensureBytes() 70 - if err != nil { 71 - return nil, err 66 + return nil, fmt.Errorf("unexpected internal error parsing own private P-256 x509 key: %w", err) 72 67 } 73 - return &priv, nil 68 + return &PrivateKeyP256{privP256: *skECDSA, privP256ecdh: skECDH}, nil 74 69 } 75 70 76 71 // Checks if the two private keys are the same. Note that the naive == operator does not work for most equality checks. 77 72 func (k *PrivateKeyP256) Equal(other PrivateKey) bool { 78 73 otherP256, ok := other.(*PrivateKeyP256) 79 74 if ok { 80 - return k.privP256.Equal(otherP256.privP256) 75 + return k.privP256.Equal(&otherP256.privP256) 81 76 } 82 77 return false 83 78 } 84 79 85 - // internal helper which checks that they key will be possible to export later 86 - func (k *PrivateKeyP256) ensureBytes() error { 87 - _, err := k.privP256.ECDH() 88 - return err 89 - } 90 - 91 80 // Serializes the secret key material in to a raw binary format, which can be parsed by [ParsePrivateBytesP256]. 92 81 // 93 82 // For P-256, this is the "compact" encoding and is 32 bytes long. There is no ASN.1 or other enclosing structure. 94 83 func (k *PrivateKeyP256) Bytes() []byte { 95 - skEcdh, err := k.privP256.ECDH() 96 - if err != nil { 97 - log.Fatal("unexpected failure to export P-256 private key, after being exportable at parse time") 98 - } 99 - return skEcdh.Bytes() 84 + return k.privP256ecdh.Bytes() 100 85 } 101 86 102 87 // Outputs the [PublicKey] corresponding to this [PrivateKeyP256]; it will be a [PublicKeyP256]. 103 88 func (k *PrivateKeyP256) Public() (PublicKey, error) { 104 - pub := PublicKeyP256{pubP256: k.privP256.Public().(*ecdsa.PublicKey)} 105 - err := pub.ensureBytes() 89 + pkECDSA, ok := k.privP256.Public().(*ecdsa.PublicKey) 90 + if !ok { 91 + return nil, fmt.Errorf("unexpected internal error casting P-256 ecdsa public key") 92 + } 93 + pkECDH, err := pkECDSA.ECDH() 106 94 if err != nil { 107 - return nil, err 95 + return nil, fmt.Errorf("unexpected internal error converting P-256 key from ecdsa to ecdh: %w", err) 108 96 } 109 - return &pub, nil 97 + return &PublicKeyP256{pubP256: *pkECDSA, pubP256ecdh: *pkECDH}, nil 110 98 } 111 99 112 100 // First hashes the raw bytes, then signs the digest, returning a binary signature. ··· 118 106 // NIST ECDSA signatures can have a "malleability" issue, meaning that there are multiple valid signatures for the same content with the same signing key. This method always returns a "low-S" signature, as required by atproto. 119 107 func (k *PrivateKeyP256) HashAndSign(content []byte) ([]byte, error) { 120 108 hash := sha256.Sum256(content) 121 - r, s, err := ecdsa.Sign(rand.Reader, k.privP256, hash[:]) 109 + r, s, err := ecdsa.Sign(rand.Reader, &k.privP256, hash[:]) 122 110 if err != nil { 123 111 return nil, fmt.Errorf("crypto error signing with P-256/secp256r1 private key: %w", err) 124 112 } ··· 141 129 if !curve.Params().IsOnCurve(x, y) { 142 130 return nil, fmt.Errorf("invalid P-256 public key (not on curve)") 143 131 } 144 - pubK := &ecdsa.PublicKey{ 132 + pubECDSA := &ecdsa.PublicKey{ 145 133 Curve: curve, 146 134 X: x, 147 135 Y: y, 148 136 } 149 - pub := PublicKeyP256{pubP256: pubK} 150 - err := pub.ensureBytes() 137 + pubECDH, err := pubECDSA.ECDH() 138 + pub := PublicKeyP256{pubP256: *pubECDSA, pubP256ecdh: *pubECDH} 139 + if err != nil { 140 + return nil, fmt.Errorf("unexpected internal error converting P-256 x509 key from ecdsa to ecdh: %w", err) 141 + } 142 + err = pub.checkCurve() 151 143 if err != nil { 152 144 return nil, err 153 145 } ··· 166 158 if !curve.Params().IsOnCurve(x, y) { 167 159 return nil, fmt.Errorf("invalid P-256 public key (not on curve)") 168 160 } 169 - pubK := &ecdsa.PublicKey{ 161 + pubECDSA := &ecdsa.PublicKey{ 170 162 Curve: curve, 171 163 X: x, 172 164 Y: y, 173 165 } 174 - pub := PublicKeyP256{pubP256: pubK} 175 - err := pub.ensureBytes() 166 + pubECDH, err := pubECDSA.ECDH() 167 + pub := PublicKeyP256{pubP256: *pubECDSA, pubP256ecdh: *pubECDH} 168 + if err != nil { 169 + return nil, fmt.Errorf("unexpected internal error converting P-256 x509 key from ecdsa to ecdh: %w", err) 170 + } 171 + err = pub.checkCurve() 176 172 if err != nil { 177 173 return nil, err 178 174 } ··· 183 179 func (k *PublicKeyP256) Equal(other PublicKey) bool { 184 180 otherP256, ok := other.(*PublicKeyP256) 185 181 if ok { 186 - return k.pubP256.Equal(otherP256.pubP256) 182 + return k.pubP256.Equal(&otherP256.pubP256) 187 183 } 188 184 return false 189 185 } 190 186 191 - // checks that key will be exportable later, both compressed and uncompressed 192 - func (k *PublicKeyP256) ensureBytes() error { 187 + func (k *PublicKeyP256) checkCurve() error { 193 188 if !k.pubP256.Curve.IsOnCurve(k.pubP256.X, k.pubP256.Y) { 194 189 return fmt.Errorf("unexpected invalid P-256/secp256r1 public key (internal)") 195 190 } 196 - _, err := k.pubP256.ECDH() 197 - return err 191 + return nil 198 192 } 199 193 200 194 // Serializes the key in to "uncompressed" binary format. 201 195 func (k *PublicKeyP256) UncompressedBytes() []byte { 202 - pkEcdh, err := k.pubP256.ECDH() 203 - if err != nil { 204 - log.Fatal("unexpected invalid P-256/secp256r1 public key, was verified at parse time") 205 - } 206 - return pkEcdh.Bytes() 196 + return k.pubP256ecdh.Bytes() 207 197 } 208 198 209 199 // Serializes the key in to "compressed" binary format. ··· 229 219 r.SetBytes(sig[:32]) 230 220 s.SetBytes(sig[32:]) 231 221 232 - if !ecdsa.Verify(k.pubP256, hash[:], r, s) { 222 + if !ecdsa.Verify(&k.pubP256, hash[:], r, s) { 233 223 return ErrInvalidSignature 234 224 } 235 225
+2 -2
atproto/crypto/w3c_didkey_test.go
··· 77 77 case "K256": 78 78 priv, err = ParsePrivateBytesK256(raw) 79 79 default: 80 - panic("impossible key type") 80 + t.Fatal("impossible key type") 81 81 } 82 82 if err != nil { 83 83 t.Fatal(err) ··· 90 90 if err != nil { 91 91 t.Fatal(err) 92 92 } 93 - assert.Equal(kBytes.Equal(kDIDKey), true) 93 + assert.True(kBytes.Equal(kDIDKey)) 94 94 assert.Equal(row.PublicDIDKey, kBytes.DIDKey()) 95 95 assert.Equal(row.PublicDIDKey, kDIDKey.DIDKey()) 96 96 }