SECStatus SGN_End(SGNContext *cx, SECItem *result) { unsigned char digest[HASH_LENGTH_MAX]; unsigned part1; int signatureLen; SECStatus rv; SECItem digder, sigitem; PLArenaPool *arena = 0; SECKEYPrivateKey *privKey = cx->key; SGNDigestInfo *di = 0; result->data = 0; digder.data = 0; /* Finish up digest function */ if (cx->hashcx == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); if (privKey->keyType == rsaKey) { arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { rv = SECFailure; goto loser; } /* Construct digest info */ di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); if (!di) { rv = SECFailure; goto loser; } /* Der encode the digest as a DigestInfo */ rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); if (rv != SECSuccess) { goto loser; } } else { digder.data = digest; digder.len = part1; } /* ** Encrypt signature after constructing appropriate PKCS#1 signature ** block */ signatureLen = PK11_SignatureLen(privKey); if (signatureLen <= 0) { PORT_SetError(SEC_ERROR_INVALID_KEY); rv = SECFailure; goto loser; } sigitem.len = signatureLen; sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); if (sigitem.data == NULL) { rv = SECFailure; goto loser; } rv = PK11_Sign(privKey, &sigitem, &digder); if (rv != SECSuccess) { PORT_Free(sigitem.data); sigitem.data = NULL; goto loser; } if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); PORT_Free(sigitem.data); if (rv != SECSuccess) goto loser; } else { result->len = sigitem.len; result->data = sigitem.data; } loser: SGN_DestroyDigestInfo(di); if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } return rv; }
SECStatus ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, PRBool isTLS, KeyType keyType) { SECStatus rv = SECFailure; PRBool doDerEncode = PR_FALSE; unsigned int signatureLen; OSStatus status = noErr; CSSM_CSP_HANDLE cspHandle = 0; const CSSM_KEY *cssmKey = NULL; CSSM_ALGORITHMS sigAlg; CSSM_ALGORITHMS digestAlg; const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; CSSM_RETURN cssmRv; CSSM_DATA hashData; CSSM_DATA signatureData; CSSM_CC_HANDLE cssmSignature = 0; const SSL3Opaque* prefix; unsigned int prefixLen; SSL3Opaque prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX]; buf->data = NULL; status = SecKeyGetCSPHandle(key, &cspHandle); if (status != noErr) { PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } status = SecKeyGetCSSMKey(key, &cssmKey); if (status != noErr || !cssmKey) { PORT_SetError(SEC_ERROR_NO_KEY); goto done; } /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the * needed information is readily available on the key itself. */ signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; if (signatureLen == 0) { PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) goto done; /* error code was set. */ sigAlg = cssmKey->KeyHeader.AlgorithmId; digestAlg = CSSM_ALGID_NONE; switch (keyType) { case rsaKey: PORT_Assert(sigAlg == CSSM_ALGID_RSA); if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) != SECSuccess) { goto done; } if (prefixLen + hash->len > sizeof(prefixAndHash)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); goto done; } memcpy(prefixAndHash, prefix, prefixLen); memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len); hashData.Data = prefixAndHash; hashData.Length = prefixLen + hash->len; break; case dsaKey: case ecKey: if (keyType == ecKey) { PORT_Assert(sigAlg == CSSM_ALGID_ECDSA); doDerEncode = PR_TRUE; } else { PORT_Assert(sigAlg == CSSM_ALGID_DSA); doDerEncode = isTLS; } if (hash->hashAlg == SEC_OID_UNKNOWN) { hashData.Data = hash->u.s.sha; hashData.Length = sizeof(hash->u.s.sha); } else { hashData.Data = hash->u.raw; hashData.Length = hash->len; } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, * you can prevent the UI by setting the provider handle on the * certificate to be opened with CRYPT_SILENT, but is there an equivalent? */ status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, kSecCredentialTypeDefault, &cssmCreds); if (status != noErr) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status); goto done; } signatureData.Length = signatureLen; signatureData.Data = (uint8*)buf->data; cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, cssmKey, &cssmSignature); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } /* See "Apple Cryptographic Service Provider Functional Specification" */ if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { /* To set RSA blinding for RSA keys */ CSSM_CONTEXT_ATTRIBUTE blindingAttr; blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; blindingAttr.AttributeLength = sizeof(uint32); blindingAttr.Attribute.Uint32 = 1; cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } } cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg, &signatureData); if (cssmRv) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); goto done; } buf->len = signatureData.Length; if (doDerEncode) { SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ } else if (derSig.data) { PORT_Free(derSig.data); } } else { rv = SECSuccess; } PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); done: /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and * should not be freed. When the PlatformKey is freed, they will be * released. */ if (cssmSignature) CSSM_DeleteContext(cssmSignature); if (rv != SECSuccess && buf->data) { PORT_Free(buf->data); buf->data = NULL; } return rv; }
static SECStatus ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, PRBool isTLS, KeyType keyType) { SECStatus rv = SECFailure; SECURITY_STATUS ncrypt_status; PRBool doDerEncode = PR_FALSE; SECItem hashItem; DWORD signatureLen = 0; DWORD dwFlags = 0; VOID *pPaddingInfo = NULL; /* Always encode using PKCS#1 block type. */ BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo; if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); return SECFailure; } if (ssl_InitCng() != SECSuccess) { PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); return SECFailure; } switch (keyType) { case rsaKey: switch (hash->hashAlg) { case SEC_OID_UNKNOWN: /* No OID/encoded DigestInfo. */ rsaPaddingInfo.pszAlgId = NULL; break; case SEC_OID_SHA1: rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; break; case SEC_OID_SHA256: rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM; break; case SEC_OID_SHA384: rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM; break; case SEC_OID_SHA512: rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM; break; default: PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); return SECFailure; } hashItem.data = hash->u.raw; hashItem.len = hash->len; dwFlags = BCRYPT_PAD_PKCS1; pPaddingInfo = &rsaPaddingInfo; break; case dsaKey: case ecKey: if (keyType == ecKey) { doDerEncode = PR_TRUE; } else { doDerEncode = isTLS; } if (hash->hashAlg == SEC_OID_UNKNOWN) { hashItem.data = hash->u.s.sha; hashItem.len = sizeof(hash->u.s.sha); } else { hashItem.data = hash->u.raw; hashItem.len = hash->len; } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo, (PBYTE)hashItem.data, hashItem.len, NULL, 0, &signatureLen, dwFlags); if (FAILED(ncrypt_status) || signatureLen == 0) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status); goto done; } buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) { goto done; /* error code was set. */ } ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo, (PBYTE)hashItem.data, hashItem.len, (PBYTE)buf->data, signatureLen, &signatureLen, dwFlags); if (FAILED(ncrypt_status) || signatureLen == 0) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status); goto done; } buf->len = signatureLen; if (doDerEncode) { SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ } else if (derSig.data) { PORT_Free(derSig.data); } } else { rv = SECSuccess; } PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); done: if (rv != SECSuccess && buf->data) { PORT_Free(buf->data); buf->data = NULL; buf->len = 0; } return rv; }
static SECStatus ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, PRBool isTLS, KeyType keyType) { SECStatus rv = SECFailure; PRBool doDerEncode = PR_FALSE; SECItem hashItem; DWORD argLen = 0; DWORD signatureLen = 0; ALG_ID hashAlg = 0; HCRYPTHASH hHash = 0; DWORD hashLen = 0; unsigned int i = 0; buf->data = NULL; switch (hash->hashAlg) { case SEC_OID_UNKNOWN: hashAlg = 0; break; case SEC_OID_SHA1: hashAlg = CALG_SHA1; break; case SEC_OID_SHA256: hashAlg = CALG_SHA_256; break; case SEC_OID_SHA384: hashAlg = CALG_SHA_384; break; case SEC_OID_SHA512: hashAlg = CALG_SHA_512; break; default: PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); return SECFailure; } switch (keyType) { case rsaKey: if (hashAlg == 0) { hashAlg = CALG_SSL3_SHAMD5; } hashItem.data = hash->u.raw; hashItem.len = hash->len; break; case dsaKey: case ecKey: if (keyType == ecKey) { doDerEncode = PR_TRUE; } else { doDerEncode = isTLS; } if (hashAlg == 0) { hashAlg = CALG_SHA1; hashItem.data = hash->u.s.sha; hashItem.len = sizeof(hash->u.s.sha); } else { hashItem.data = hash->u.raw; hashItem.len = hash->len; } break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); goto done; } PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); goto done; } argLen = sizeof(hashLen); if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); goto done; } if (hashLen != hashItem.len) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, 0); goto done; } if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); goto done; } if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, NULL, &signatureLen) || signatureLen == 0) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); goto done; } buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) goto done; /* error code was set. */ if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, (BYTE*)buf->data, &signatureLen)) { PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); goto done; } buf->len = signatureLen; /* CryptoAPI signs in little-endian, so reverse */ for (i = 0; i < buf->len / 2; ++i) { unsigned char tmp = buf->data[i]; buf->data[i] = buf->data[buf->len - 1 - i]; buf->data[buf->len - 1 - i] = tmp; } if (doDerEncode) { SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ } else if (derSig.data) { PORT_Free(derSig.data); } } else { rv = SECSuccess; } PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); done: if (hHash) CryptDestroyHash(hHash); if (rv != SECSuccess && buf->data) { PORT_Free(buf->data); buf->data = NULL; } return rv; }
SECStatus SGN_End(SGNContext *cx, SECItem *result) { unsigned char digest[HASH_LENGTH_MAX]; unsigned part1; int signatureLen; SECStatus rv; SECItem digder, sigitem; PLArenaPool *arena = 0; SECKEYPrivateKey *privKey = cx->key; SGNDigestInfo *di = 0; result->data = 0; digder.data = 0; sigitem.data = 0; /* Finish up digest function */ if (cx->hashcx == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } (*cx->hashobj->end)(cx->hashcx, digest, &part1, sizeof(digest)); if (privKey->keyType == rsaKey && cx->signalg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { rv = SECFailure; goto loser; } /* Construct digest info */ di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); if (!di) { rv = SECFailure; goto loser; } /* Der encode the digest as a DigestInfo */ rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); if (rv != SECSuccess) { goto loser; } } else { digder.data = digest; digder.len = part1; } /* ** Encrypt signature after constructing appropriate PKCS#1 signature ** block */ signatureLen = PK11_SignatureLen(privKey); if (signatureLen <= 0) { PORT_SetError(SEC_ERROR_INVALID_KEY); rv = SECFailure; goto loser; } sigitem.len = signatureLen; sigitem.data = (unsigned char *)PORT_Alloc(signatureLen); if (sigitem.data == NULL) { rv = SECFailure; goto loser; } if (cx->signalg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { CK_RSA_PKCS_PSS_PARAMS mech; SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) }; PORT_Memset(&mech, 0, sizeof(mech)); if (cx->params && cx->params->data) { SECKEYRSAPSSParams params; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) { rv = SECFailure; goto loser; } PORT_Memset(¶ms, 0, sizeof(params)); rv = SEC_QuickDERDecodeItem(arena, ¶ms, SECKEY_RSAPSSParamsTemplate, cx->params); if (rv != SECSuccess) { goto loser; } rv = sec_RSAPSSParamsToMechanism(&mech, ¶ms); if (rv != SECSuccess) { goto loser; } } else { mech.hashAlg = CKM_SHA_1; mech.mgf = CKG_MGF1_SHA1; mech.sLen = digder.len; } rv = PK11_SignWithMechanism(privKey, CKM_RSA_PKCS_PSS, &mechItem, &sigitem, &digder); if (rv != SECSuccess) { goto loser; } } else { rv = PK11_Sign(privKey, &sigitem, &digder); if (rv != SECSuccess) { goto loser; } } if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); if (rv != SECSuccess) goto loser; SECITEM_FreeItem(&sigitem, PR_FALSE); } else { result->len = sigitem.len; result->data = sigitem.data; } loser: if (rv != SECSuccess) { SECITEM_FreeItem(&sigitem, PR_FALSE); } SGN_DestroyDigestInfo(di); if (arena != NULL) { PORT_FreeArena(arena, PR_FALSE); } return rv; }