func()

in aws_signing_helper/cert_store_signer_windows.go [471:540]


func (signer *WindowsCertStoreSigner) cngSignHash(digest []byte, hash crypto.Hash) ([]byte, error) {
	if len(digest) != hash.Size() {
		return nil, errors.New("bad digest for hash")
	}

	var (
		// Input
		padPtr    = unsafe.Pointer(nil)
		digestPtr = (*C.BYTE)(&digest[0])
		digestLen = C.DWORD(len(digest))
		flags     = C.DWORD(0)

		// Output
		sigLen = C.DWORD(0)
	)

	// Set up pkcs1v1.5 padding for RSA
	privateKey, _ := signer.getPrivateKey()
	if _, isRSA := privateKey.publicKey.(*rsa.PublicKey); isRSA {
		flags |= C.BCRYPT_PAD_PKCS1
		padInfo := C.BCRYPT_PKCS1_PADDING_INFO{}
		padPtr = unsafe.Pointer(&padInfo)

		switch hash {
		case crypto.SHA1:
			padInfo.pszAlgId = C.GET_BCRYPT_SHA1_ALGORITHM()
		case crypto.SHA256:
			padInfo.pszAlgId = C.GET_BCRYPT_SHA256_ALGORITHM()
		case crypto.SHA384:
			padInfo.pszAlgId = C.GET_BCRYPT_SHA384_ALGORITHM()
		case crypto.SHA512:
			padInfo.pszAlgId = C.GET_BCRYPT_SHA512_ALGORITHM()
		default:
			return nil, ErrUnsupportedHash
		}
	}

	// Get C.NCRYPT_KEY_HANDLE in order to do the signature
	cngKeyHandle := (*C.NCRYPT_KEY_HANDLE)(unsafe.Pointer(&privateKey.cngKeyHandle))

	// Get signature length
	if err := checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, nil, 0, &sigLen, flags)); err != nil {
		return nil, fmt.Errorf("failed to get signature length: %w", err)
	}

	// Get signature
	sig := make([]byte, sigLen)
	sigPtr := (*C.BYTE)(&sig[0])
	if err := checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, sigPtr, sigLen, &sigLen, flags|C.NCRYPT_SILENT_FLAG)); err != nil {
		if err == ErrRequiresUI {
			if err = checkStatus(C.NCryptSignHash(*cngKeyHandle, padPtr, digestPtr, digestLen, sigPtr, sigLen, &sigLen, flags)); err == nil {
				goto got_signature
			}
		}

		return nil, fmt.Errorf("failed to sign digest: %w", err)
	}
got_signature:

	// CNG returns a raw ECDSA signature, but we want ASN.1 DER encoding
	if _, isEC := privateKey.publicKey.(*ecdsa.PublicKey); isEC {
		if len(sig)%2 != 0 {
			return nil, errors.New("bad ecdsa signature from CNG")
		}

		return encodeEcdsaSigValue(sig)
	}

	return sig, nil
}