]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/crypto/x509/x509.go
Use GoGOST's PublicKey wrappers
[gostls13.git] / src / crypto / x509 / x509.go
index c72010c1e38830e29a3b520caea6619dc4cb9b12..494c3b37fb928fc52e0f5b9b7567ca31496b8240 100644 (file)
@@ -49,6 +49,7 @@ import (
        _ "crypto/sha256"
        _ "crypto/sha512"
 
+       "crypto/go.cypherpunks.ru/gogost/v5/gost3410"
        "golang.org/x/crypto/cryptobyte"
        cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
 )
@@ -131,6 +132,63 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A
                        }
                        publicKeyAlgorithm.Parameters.FullBytes = paramBytes
                }
+       case *gost3410.PublicKey:
+               builder := cryptobyte.NewBuilder(nil)
+               builder.AddASN1OctetString(pub.Raw())
+               publicKeyBytes, err = builder.Bytes()
+               if err != nil {
+                       return
+               }
+               params := GostR341012PublicKeyParameters{}
+               switch pub.C.Name {
+               case "id-GostR3410-2001-CryptoPro-A-ParamSet":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidGostR34102001CryptoProAParamSet
+                       params.DigestParamSet = oidTc26Gost34112012256
+               case "id-GostR3410-2001-CryptoPro-B-ParamSet":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidGostR34102001CryptoProBParamSet
+                       params.DigestParamSet = oidTc26Gost34112012256
+               case "id-GostR3410-2001-CryptoPro-C-ParamSet":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidGostR34102001CryptoProCParamSet
+                       params.DigestParamSet = oidTc26Gost34112012256
+               case "id-GostR3410-2001-CryptoPro-XchA-ParamSet":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidGostR34102001CryptoProXchAParamSet
+                       params.DigestParamSet = oidTc26Gost34112012256
+               case "id-GostR3410-2001-CryptoPro-XchB-ParamSet":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidGostR34102001CryptoProXchBParamSet
+                       params.DigestParamSet = oidTc26Gost34112012256
+               case "id-tc26-gost-3410-12-256-paramSetA":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidTc26Gost341012256ParamSetA
+               case "id-tc26-gost-3410-12-256-paramSetB":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidTc26Gost341012256ParamSetB
+               case "id-tc26-gost-3410-12-256-paramSetC":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidTc26Gost341012256ParamSetC
+               case "id-tc26-gost-3410-12-256-paramSetD":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+                       params.PublicKeyParamSet = oidTc26Gost341012256ParamSetD
+               case "id-tc26-gost-3410-12-512-paramSetA":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+                       params.PublicKeyParamSet = oidTc26Gost341012512ParamSetA
+               case "id-tc26-gost-3410-12-512-paramSetB":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+                       params.PublicKeyParamSet = oidTc26Gost341012512ParamSetB
+               case "id-tc26-gost-3410-12-512-paramSetC":
+                       publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+                       params.PublicKeyParamSet = oidTc26Gost341012512ParamSetC
+               default:
+                       return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported GOST elliptic curve")
+               }
+               publicKeyAlgorithm.Parameters.FullBytes, err = asn1.Marshal(params)
+               if err != nil {
+                       panic(err)
+               }
        default:
                return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub)
        }
@@ -230,6 +288,8 @@ const (
        SHA384WithRSAPSS
        SHA512WithRSAPSS
        PureEd25519
+       GOST256
+       GOST512
 )
 
 func (algo SignatureAlgorithm) isRSAPSS() bool {
@@ -258,6 +318,7 @@ const (
        DSA // Only supported for parsing.
        ECDSA
        Ed25519
+       GOST
 )
 
 var publicKeyAlgoName = [...]string{
@@ -265,6 +326,7 @@ var publicKeyAlgoName = [...]string{
        DSA:     "DSA",
        ECDSA:   "ECDSA",
        Ed25519: "Ed25519",
+       GOST:    "GOST",
 }
 
 func (algo PublicKeyAlgorithm) String() string {
@@ -340,6 +402,25 @@ var (
        oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
        oidSignatureEd25519         = asn1.ObjectIdentifier{1, 3, 101, 112}
 
+       oidTc26Gost341012256                  = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 1, 1}
+       oidTc26Gost341012512                  = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 1, 2}
+       oidTc26Gost34112012256                = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 2, 2}
+       oidTc26Gost34112012512                = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 2, 3}
+       oidTc26Gost341012256Signature         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 3, 2}
+       oidTc26Gost341012512Signature         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 3, 3}
+       oidGostR34102001CryptoProAParamSet    = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 1}
+       oidGostR34102001CryptoProBParamSet    = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 2}
+       oidGostR34102001CryptoProCParamSet    = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 3}
+       oidGostR34102001CryptoProXchAParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 36, 0}
+       oidGostR34102001CryptoProXchBParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 36, 1}
+       oidTc26Gost341012256ParamSetA         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 1}
+       oidTc26Gost341012256ParamSetB         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 2}
+       oidTc26Gost341012256ParamSetC         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 3}
+       oidTc26Gost341012256ParamSetD         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 4}
+       oidTc26Gost341012512ParamSetA         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 1}
+       oidTc26Gost341012512ParamSetB         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 2}
+       oidTc26Gost341012512ParamSetC         = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 3}
+
        oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
        oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
        oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
@@ -376,6 +457,8 @@ var signatureAlgorithmDetails = []struct {
        {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
        {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
        {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
+       {GOST256, "GOST256", oidTc26Gost341012256Signature, GOST, crypto.GOSTR34112012256},
+       {GOST512, "GOST512", oidTc26Gost341012512Signature, GOST, crypto.GOSTR34112012512},
 }
 
 // hashToPSSParameters contains the DER encoded RSA PSS parameters for the
@@ -482,6 +565,9 @@ var (
        //      id-Ed25519   OBJECT IDENTIFIER ::= { 1 3 101 112 }
        oidPublicKeyX25519  = asn1.ObjectIdentifier{1, 3, 101, 110}
        oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+
+       oidPublicKeyGOST256 = oidTc26Gost341012256
+       oidPublicKeyGOST512 = oidTc26Gost341012512
 )
 
 // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm
@@ -497,6 +583,10 @@ func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm
                return ECDSA
        case oid.Equal(oidPublicKeyEd25519):
                return Ed25519
+       case oid.Equal(oidPublicKeyGOST256):
+               return GOST
+       case oid.Equal(oidPublicKeyGOST512):
+               return GOST
        }
        return UnknownPublicKeyAlgorithm
 }
@@ -815,8 +905,10 @@ func (c *Certificate) hasSANExtension() bool {
        return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
 }
 
-// CheckSignatureFrom verifies that the signature on c is a valid signature
-// from parent. SHA1WithRSA and ECDSAWithSHA1 signatures are not supported.
+// CheckSignatureFrom verifies that the signature on c is a valid signature from parent.
+//
+// This is a low-level API that performs very limited checks, and not a full
+// path verifier. Most users should use [Certificate.Verify] instead.
 func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
        // RFC 5280, 4.2.1.9:
        // "If the basic constraints extension is not present in a version 3
@@ -836,13 +928,16 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
                return ErrUnsupportedAlgorithm
        }
 
-       // TODO(agl): don't ignore the path length constraint.
-
        return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false)
 }
 
 // CheckSignature verifies that signature is a valid signature over signed from
 // c's public key.
+//
+// This is a low-level API that performs no validity checks on the certificate.
+//
+// [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1]
+// signatures are currently accepted.
 func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
        return checkSignature(algo, signed, signature, c.PublicKey, true)
 }
@@ -927,6 +1022,18 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
                        return errors.New("x509: Ed25519 verification failure")
                }
                return
+       case *gost3410.PublicKey:
+               if pubKeyAlgo != GOST {
+                       return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
+               }
+               ok, err := gost3410.PublicKeyReverseDigest{Pub: pub}.VerifyDigest(signed, signature)
+               if err != nil {
+                       return err
+               }
+               if !ok {
+                       return errors.New("x509: GOST verification failure")
+               }
+               return err
        }
        return ErrUnsupportedAlgorithm
 }
@@ -1427,8 +1534,19 @@ func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (ha
                pubType = Ed25519
                sigAlgo.Algorithm = oidSignatureEd25519
 
+       case *gost3410.PublicKey:
+               pubType = GOST
+               switch pub.C.PointSize() {
+               case 256 / 8:
+                       hashFunc = crypto.GOSTR34112012256
+                       sigAlgo.Algorithm = oidTc26Gost341012256Signature
+               case 512 / 8:
+                       hashFunc = crypto.GOSTR34112012512
+                       sigAlgo.Algorithm = oidTc26Gost341012512Signature
+               }
+
        default:
-               err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
+               err = errors.New("x509: only RSA, ECDSA, Ed25519 and GOST keys supported")
        }
 
        if err != nil {