_ "crypto/sha256"
_ "crypto/sha512"
+ "crypto/go.cypherpunks.ru/gogost/v5/gost3410"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
publicKeyBytes = pub
publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
case *ecdh.PublicKey:
- if pub.Curve() != ecdh.X25519() {
- return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported ECDH curve")
- }
publicKeyBytes = pub.Bytes()
- publicKeyAlgorithm.Algorithm = oidPublicKeyX25519
+ if pub.Curve() == ecdh.X25519() {
+ publicKeyAlgorithm.Algorithm = oidPublicKeyX25519
+ } else {
+ oid, ok := oidFromECDHCurve(pub.Curve())
+ if !ok {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
+ }
+ publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
+ var paramBytes []byte
+ paramBytes, err = asn1.Marshal(oid)
+ if err != nil {
+ return
+ }
+ 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)
}
// (see RFC 5280, Section 4.1).
//
// The following key types are currently supported: *rsa.PublicKey,
-// *ecdsa.PublicKey, ed25519.PublicKey (not a pointer), and *ecdh.PublicKey
-// (X25519 only). Unsupported key types result in an error.
+// *ecdsa.PublicKey, ed25519.PublicKey (not a pointer), and *ecdh.PublicKey.
+// Unsupported key types result in an error.
//
// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
func MarshalPKIXPublicKey(pub any) ([]byte, error) {
SHA384WithRSAPSS
SHA512WithRSAPSS
PureEd25519
+ GOST256
+ GOST512
)
func (algo SignatureAlgorithm) isRSAPSS() bool {
DSA // Only supported for parsing.
ECDSA
Ed25519
+ GOST
)
var publicKeyAlgoName = [...]string{
DSA: "DSA",
ECDSA: "ECDSA",
Ed25519: "Ed25519",
+ GOST: "GOST",
}
func (algo PublicKeyAlgorithm) String() string {
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}
{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
// 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
return ECDSA
case oid.Equal(oidPublicKeyEd25519):
return Ed25519
+ case oid.Equal(oidPublicKeyGOST256):
+ return GOST
+ case oid.Equal(oidPublicKeyGOST512):
+ return GOST
}
return UnknownPublicKeyAlgorithm
}
return nil, false
}
+func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) {
+ switch curve {
+ case ecdh.X25519():
+ return oidPublicKeyX25519, true
+ case ecdh.P256():
+ return oidNamedCurveP256, true
+ case ecdh.P384():
+ return oidNamedCurveP384, true
+ case ecdh.P521():
+ return oidNamedCurveP521, true
+ }
+
+ return nil, false
+}
+
// KeyUsage represents the set of actions that are valid for a given key. It's
// a bitmap of the KeyUsage* constants.
type KeyUsage int
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
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)
}
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
}
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 {