func()

in aws_signing_helper/cert_store_signer_windows.go [543:623]


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

	// Figure out which CryptoAPI hash algorithm we're using
	var hash_alg C.ALG_ID

	switch hash {
	case crypto.SHA1:
		hash_alg = C.CALG_SHA1
	case crypto.SHA256:
		hash_alg = C.CALG_SHA_256
	case crypto.SHA384:
		hash_alg = C.CALG_SHA_384
	case crypto.SHA512:
		hash_alg = C.CALG_SHA_512
	default:
		return nil, ErrUnsupportedHash
	}

	// Instantiate a CryptoAPI hash object
	var cryptoHash C.HCRYPTHASH

	privateKey, _ := signer.getPrivateKey()
	cspHandle := (*C.HCRYPTPROV)(unsafe.Pointer(&privateKey.cspHandle))
	if ok := C.CryptCreateHash(*cspHandle, hash_alg, 0, 0, &cryptoHash); ok == WIN_FALSE {
		if err := lastError("failed to create hash"); errCause(err) == errCode(NTE_BAD_ALGID) {
			return nil, ErrUnsupportedHash
		} else {
			return nil, err
		}
	}
	defer C.CryptDestroyHash(cryptoHash)

	// Make sure the hash size matches
	var (
		hashSize    C.DWORD
		hashSizePtr = (*C.BYTE)(unsafe.Pointer(&hashSize))
		hashSizeLen = C.DWORD(unsafe.Sizeof(hashSize))
	)

	if ok := C.CryptGetHashParam(cryptoHash, C.HP_HASHSIZE, hashSizePtr, &hashSizeLen, 0); ok == WIN_FALSE {
		return nil, lastError("failed to get hash size")
	}

	if hash.Size() != int(hashSize) {
		return nil, errors.New("invalid CryptoAPI hash")
	}

	// Put our digest into the hash object
	digestPtr := (*C.BYTE)(unsafe.Pointer(&digest[0]))
	if ok := C.CryptSetHashParam(cryptoHash, C.HP_HASHVAL, digestPtr, 0); ok == WIN_FALSE {
		return nil, lastError("failed to set hash digest")
	}

	// Get signature length
	var sigLen C.DWORD

	if ok := C.CryptSignHash(cryptoHash, C.ulong(privateKey.keySpec), nil, 0, nil, &sigLen); ok == WIN_FALSE {
		return nil, lastError("failed to get signature length")
	}

	// Get signature
	var (
		sig    = make([]byte, int(sigLen))
		sigPtr = (*C.BYTE)(unsafe.Pointer(&sig[0]))
	)

	if ok := C.CryptSignHash(cryptoHash, C.ulong(privateKey.keySpec), nil, 0, sigPtr, &sigLen); ok == WIN_FALSE {
		return nil, lastError("failed to sign digest")
	}

	// Reversing signature since it is little endian, but we want big endian
	for i := len(sig)/2 - 1; i >= 0; i-- {
		opp := len(sig) - 1 - i
		sig[i], sig[opp] = sig[opp], sig[i]
	}

	return sig, nil
}