/*
* Platform specific crypto wrappers
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the Netscape security libraries.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1994-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ryan Sleevi <ryan.sleevi@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* $Id$ */
#include "certt.h"
#include "cryptohi.h"
#include "keythi.h"
#include "nss.h"
#include "secitem.h"
#include "ssl.h"
#include "sslimpl.h"
#include "prerror.h"
#include "prinit.h"
#ifdef NSS_PLATFORM_CLIENT_AUTH
#ifdef XP_WIN32
#include <NCrypt.h>
#endif
#endif
#ifdef NSS_PLATFORM_CLIENT_AUTH
CERTCertificateList*
hack_NewCertificateListFromCertList(CERTCertList* list)
{
CERTCertificateList * chain = NULL;
PLArenaPool * arena = NULL;
CERTCertListNode * node;
int len;
if (CERT_LIST_EMPTY(list))
goto loser;
arena = PORT_NewArena(4096);
if (arena == NULL)
goto loser;
for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
len++, node = CERT_LIST_NEXT(node)) {
}
chain = PORT_ArenaNew(arena, CERTCertificateList);
if (chain == NULL)
goto loser;
chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
if (!chain->certs)
goto loser;
chain->len = len;
for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
len++, node = CERT_LIST_NEXT(node)) {
// Check to see if the last cert to be sent is a self-signed cert,
// and if so, omit it from the list of certificates. However, if
// there is only one cert (len == 0), include the cert, as it means
// the EE cert is self-signed.
if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) {
chain->len = len;
break;
}
SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
}
chain->arena = arena;
return chain;
loser:
if (arena) {
PORT_FreeArena(arena, PR_FALSE);
}
return NULL;
}
#if defined(XP_WIN32)
typedef SECURITY_STATUS (WINAPI *NCryptFreeObjectFunc)(NCRYPT_HANDLE);
typedef SECURITY_STATUS (WINAPI *NCryptSignHashFunc)(
NCRYPT_KEY_HANDLE /* hKey */,
VOID* /* pPaddingInfo */,
PBYTE /* pbHashValue */,
DWORD /* cbHashValue */,
PBYTE /* pbSignature */,
DWORD /* cbSignature */,
DWORD* /* pcbResult */,
DWORD /* dwFlags */);
static PRCallOnceType cngFunctionsInitOnce;
static const PRCallOnceType pristineCallOnce;
static PRLibrary *ncrypt_library = NULL;
static NCryptFreeObjectFunc pNCryptFreeObject = NULL;
static NCryptSignHashFunc pNCryptSignHash = NULL;
static SECStatus
ssl_ShutdownCngFunctions(void *appData, void *nssData)
{
pNCryptSignHash = NULL;
pNCryptFreeObject = NULL;
if (ncrypt_library) {
PR_UnloadLibrary(ncrypt_library);
ncrypt_library = NULL;
}
cngFunctionsInitOnce = pristineCallOnce;
return SECSuccess;
}
static PRStatus
ssl_InitCngFunctions(void)
{
SECStatus rv;
ncrypt_library = PR_LoadLibrary("ncrypt.dll");
if (ncrypt_library == NULL)
goto loser;
pNCryptFreeObject = (NCryptFreeObjectFunc)PR_FindFunctionSymbol(
ncrypt_library, "NCryptFreeObject");
if (pNCryptFreeObject == NULL)
goto loser;
pNCryptSignHash = (NCryptSignHashFunc)PR_FindFunctionSymbol(
ncrypt_library, "NCryptSignHash");
if (pNCryptSignHash == NULL)
goto loser;
rv = NSS_RegisterShutdown(ssl_ShutdownCngFunctions, NULL);
if (rv != SECSuccess)
goto loser;
return PR_SUCCESS;
loser:
pNCryptSignHash = NULL;
pNCryptFreeObject = NULL;
if (ncrypt_library) {
PR_UnloadLibrary(ncrypt_library);
ncrypt_library = NULL;
}
return PR_FAILURE;
}
static SECStatus
ssl_InitCng(void)
{
if (PR_CallOnce(&cngFunctionsInitOnce, ssl_InitCngFunctions) != PR_SUCCESS)
return SECFailure;
return SECSuccess;
}
void
ssl_FreePlatformKey(PlatformKey key)
{
if (!key)
return;
if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
if (ssl_InitCng() == SECSuccess) {
(*pNCryptFreeObject)(key->hNCryptKey);
}
} else {
CryptReleaseContext(key->hCryptProv, 0);
}
PORT_Free(key);
}
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
ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
PRBool isTLS, KeyType keyType)
{
if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
return ssl3_CngPlatformSignHashes(hash, key, buf, isTLS, keyType);
}
return ssl3_CAPIPlatformSignHashes(hash, key, buf, isTLS, keyType);
}
#elif defined(XP_MACOSX)
#include <Security/cssm.h>
void
ssl_FreePlatformKey(PlatformKey key)
{
CFRelease(key);
}
#define SSL_MAX_DIGEST_INFO_PREFIX 20
/* ssl3_GetDigestInfoPrefix sets |out| and |out_len| to point to a buffer that
* contains ASN.1 data that should be prepended to a hash of the given type in
* order to create a DigestInfo structure that is valid for use in a PKCS #1
* v1.5 RSA signature. |out_len| will not be set to a value greater than
* SSL_MAX_DIGEST_INFO_PREFIX. */
static SECStatus
ssl3_GetDigestInfoPrefix(SECOidTag hashAlg,
const SSL3Opaque** out, unsigned int *out_len)
{
/* These are the DER encoding of ASN.1 DigestInfo structures:
* DigestInfo ::= SEQUENCE {
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
* See PKCS #1 v2.2 Section 9.2, Note 1.
*/
static const unsigned char kSHA1[] = {
0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
};
static const unsigned char kSHA224[] = {
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
0x00, 0x04, 0x1c
};
static const unsigned char kSHA256[] = {
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20
};
static const unsigned char kSHA384[] = {
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
0x00, 0x04, 0x30
};
static const unsigned char kSHA512[] = {
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40
};
switch (hashAlg) {
case SEC_OID_UNKNOWN:
*out_len = 0;
break;
case SEC_OID_SHA1:
*out = kSHA1;
*out_len = sizeof(kSHA1);
break;
case SEC_OID_SHA224:
*out = kSHA224;
*out_len = sizeof(kSHA224);
break;
case SEC_OID_SHA256:
*out = kSHA256;
*out_len = sizeof(kSHA256);
break;
case SEC_OID_SHA384:
*out = kSHA384;
*out_len = sizeof(kSHA384);
break;
case SEC_OID_SHA512:
*out = kSHA512;
*out_len = sizeof(kSHA512);
break;
default:
PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
return SECFailure;
}
return SECSuccess;
}
/* Given the length of a raw DSA signature (consisting of two integers
* r and s), returns the maximum length of the DER encoding of the
* following structure:
*
* Dss-Sig-Value ::= SEQUENCE {
* r INTEGER,
* s INTEGER
* }
*/
static unsigned int
ssl3_DSAMaxDerEncodedLength(unsigned int rawDsaLen)
{
/* The length of one INTEGER. */
unsigned int integerDerLen = rawDsaLen/2 + /* the integer itself */
1 + /* additional zero byte if high bit is 1 */
SEC_ASN1LengthLength(rawDsaLen/2 + 1) + /* length */
1; /* INTEGER tag */
/* The length of two INTEGERs in a SEQUENCE */
return 2 * integerDerLen + /* two INTEGERs */
SEC_ASN1LengthLength(2 * integerDerLen) + /* length */
1; /* SEQUENCE tag */
}
SECStatus
ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
PRBool isTLS, KeyType keyType)
{
SECStatus rv = SECFailure;
PRBool doDerDecode = PR_FALSE;
unsigned int rawDsaLen;
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;
}
sigAlg = cssmKey->KeyHeader.AlgorithmId;
digestAlg = CSSM_ALGID_NONE;
switch (keyType) {
case rsaKey:
PORT_Assert(sigAlg == CSSM_ALGID_RSA);
signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
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:
/* SSL3 DSA signatures are raw, not DER-encoded. CSSM gives back
* DER-encoded signatures, so they must be decoded. */
doDerDecode = (keyType == dsaKey) && !isTLS;
/* Compute the maximum size of a DER-encoded signature: */
if (keyType == ecKey) {
PORT_Assert(sigAlg == CSSM_ALGID_ECDSA);
/* LogicalKeySizeInBits is the size of an EC public key. But an
* ECDSA signature length depends on the size of the base
* point's order. For P-256, P-384, and P-521, these two sizes
* are the same. */
rawDsaLen =
(cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8 * 2;
} else {
/* TODO(davidben): Get the size of the subprime out of CSSM. For
* now, assume 160; Apple's implementation hardcodes it. */
PORT_Assert(sigAlg == CSSM_ALGID_DSA);
rawDsaLen = 2 * (160 / 8);
}
signatureLen = ssl3_DSAMaxDerEncodedLength(rawDsaLen);
/* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated
* hash. In that case, we use just the SHA1 part. */
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));
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. */
/* 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 (doDerDecode) {
SECItem* rawSig = DSAU_DecodeDerSigToLen(buf, rawDsaLen);
if (rawSig != NULL) {
PORT_Free(buf->data); /* discard encoded signature. */
*buf = *rawSig; /* give caller unencoded signature. */
PORT_Free(rawSig);
rv = SECSuccess;
}
} 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;
}
#else
void
ssl_FreePlatformKey(PlatformKey key)
{
}
SECStatus
ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
PRBool isTLS, KeyType keyType)
{
PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
return SECFailure;
}
#endif
#endif /* NSS_PLATFORM_CLIENT_AUTH */