golang/go · error

crypto/rsa: unsupported hash function: %d

Error message

crypto/rsa: unsupported hash function: %d

What it means

Thrown by the BoringCrypto backend of crypto/rsa when SignRSAPKCS1v15 is called with a crypto.Hash value that cryptoHashToMD does not map to a known BoringSSL EVP_MD. The integer value of the hash is appended so you can see exactly which crypto.Hash constant was rejected. It only fires on the BoringCrypto code path (GOEXPERIMENT=boringcrypto or a BoringCrypto-built Go toolchain).

Source

Thrown at src/crypto/internal/boring/rsa.go:336

func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
	if h == 0 {
		// No hashing.
		var out []byte
		var outLen C.size_t
		if priv.withKey(func(key *C.GO_RSA) C.int {
			out = make([]byte, C._goboringcrypto_RSA_size(key))
			return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)),
				base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING)
		}) == 0 {
			return nil, fail("RSA_sign_raw")
		}
		return out[:outLen], nil
	}

	md := cryptoHashToMD(h)
	if md == nil {
		return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h)))
	}
	nid := C._goboringcrypto_EVP_MD_type(md)
	var out []byte
	var outLen C.uint
	if priv.withKey(func(key *C.GO_RSA) C.int {
		out = make([]byte, C._goboringcrypto_RSA_size(key))
		return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)),
			base(out), &outLen, key)
	}) == 0 {
		return nil, fail("RSA_sign")
	}
	return out[:outLen], nil
}

func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
	if h == 0 {
		var out []byte
		var outLen C.size_t

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Check the numeric value reported in the message against the crypto.Hash constants in crypto.go and switch to one BoringCrypto supports (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, or the SHA-512 truncations).
  2. If you need a hash BoringCrypto does not support, hash the data yourself with h==0 (raw signing) and pass the precomputed digest, or use a non-BoringCrypto build of Go.
  3. Ensure you are not passing an uninitialized crypto.Hash variable (value 0 means 'no hash' and takes a different branch).

Example fix

// before
sig, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.Hash(7), digest) // 7 is not supported
// after
sig, err := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, digest)
Defensive patterns

Strategy: validation

Validate before calling

// allowed hashes on the BoringCrypto backend
var boringSupportedHashes = map[crypto.Hash]bool{
    crypto.MD5SHA1: true, crypto.SHA1: true, crypto.SHA224: true,
    crypto.SHA256: true, crypto.SHA384: true, crypto.SHA512: true,
    crypto.SHA512_224: true, crypto.SHA512_256: true,
}
func canSignPKCS1v15(h crypto.Hash) bool { return h == 0 || boringSupportedHashes[h] }

Type guard

// n/a: crypto.Hash is an untyped int constant; guard with an allow-set check above.

Try / catch

sig, err := rsa.SignPKCS1v15(rand.Reader, priv, h, digest)
if err != nil {
    if strings.Contains(err.Error(), "unsupported hash function") {
        // h not supported by current backend; fall back to a supported hash
    }
    return err
}

Prevention

When it happens

Trigger: Calling rsa.SignPKCS1v15(priv, h, hashed) where h is not 0 and not one of crypto.MD5SHA1, crypto.SHA1, crypto.SHA224, crypto.SHA256, crypto.SHA384, crypto.SHA512, crypto.SHA512_224, crypto.SHA512_256 (the set cryptoHashToMD knows), while running with the BoringCrypto build.

Common situations: Passing a newer or uncommon crypto.Hash (e.g. SHA3, BLAKE2) to PKCS1v15 signing; passing a zero-valued-but-not-zero crypto.Hash variable; code that worked on the standard crypto/rsa backend but fails when the binary is built with BoringCrypto because BoringCrypto supports a smaller hash set.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/26613336200c68fe. Report an issue: GitHub.