From 434a7dab92acb8281e7e7f18a149e257be119f14 Mon Sep 17 00:00:00 2001 From: Alexander Scheel Date: Tue, 19 Oct 2021 14:35:55 -0400 Subject: [PATCH] Restrict ECDSA signatures with NIST P-Curve hashes When using an ECDSA signature with a NIST P-Curve, we should follow recommendations from BIS (Section 4.2) and Mozilla's root store policy (section 5.1.2) to ensure that arbitrary selection of signature_bits does not exceed what the curve is capable of signing. Related: #11245 Signed-off-by: Alexander Scheel --- sdk/helper/certutil/helpers.go | 46 +++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/sdk/helper/certutil/helpers.go b/sdk/helper/certutil/helpers.go index 9b7bb3cc3a08f..c46530d6894de 100644 --- a/sdk/helper/certutil/helpers.go +++ b/sdk/helper/certutil/helpers.go @@ -33,6 +33,14 @@ import ( cbasn1 "golang.org/x/crypto/cryptobyte/asn1" ) +// Mapping of NIST P-Curve's key length to expected signature bits. +var expectedNISTPCurveHashBits = map[int]int{ + 224: 256, + 256: 256, + 384: 384, + 521: 512, +} + // GetHexFormatted returns the byte buffer formatted in hex with // the specified separator between bytes. func GetHexFormatted(buf []byte, sep string) string { @@ -514,13 +522,45 @@ func StringToOid(in string) (asn1.ObjectIdentifier, error) { return asn1.ObjectIdentifier(ret), nil } -func ValidateSignatureLength(keyBits int) error { - switch keyBits { +// Validates that the combination of keyType, keyBits, and hashBits are +// valid together; replaces individual calls to ValidateSignatureLength and +// ValidateKeyTypeLength. +func ValidateKeyTypeSignatureLength(keyType string, keyBits int, hashBits int) error { + if err := ValidateKeyTypeLength(keyType, keyBits); err != nil { + return err + } + + if err := ValidateSignatureLength(hashBits); err != nil { + return err + } + + if keyType == "ec" { + // To comply with BSI recommendations Section 4.2 and Mozilla root + // store policy section 5.1.2, enforce that NIST P-curves use a hash + // length corresponding to curve length. Note that ed25519 does not + // the "ec" key type. + expectedHashBits, present := expectedNISTPCurveHashBits[keyBits] + if !present { + panic(fmt.Sprintf("Unexpected NIST P-curve key length approved by ValidateKeyTypeLength: %d", keyBits)) + } + + if expectedHashBits != hashBits { + return fmt.Errorf("unsupported signature hash algorithm length (%d) for NIST P-%d", hashBits, keyBits) + } + } + + return nil +} + +// Validates that the length of the hash (in bits) used in the signature +// calculation is a known, approved value. +func ValidateSignatureLength(hashBits int) error { + switch hashBits { case 256: case 384: case 512: default: - return fmt.Errorf("unsupported signature algorithm: %d", keyBits) + return fmt.Errorf("unsupported hash signature algorithm: %d", hashBits) } return nil }