sslplatf.c revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1/*
2 * Platform specific crypto wrappers
3 *
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is the Netscape security libraries.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *   Ryan Sleevi <ryan.sleevi@gmail.com>
26 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40/* $Id$ */
41#include "certt.h"
42#include "cryptohi.h"
43#include "keythi.h"
44#include "nss.h"
45#include "secitem.h"
46#include "ssl.h"
47#include "sslimpl.h"
48#include "prerror.h"
49#include "prinit.h"
50
51#ifdef NSS_PLATFORM_CLIENT_AUTH
52#ifdef XP_WIN32
53#include <NCrypt.h>
54#endif
55#endif
56
57#ifdef NSS_PLATFORM_CLIENT_AUTH
58CERTCertificateList*
59hack_NewCertificateListFromCertList(CERTCertList* list)
60{
61    CERTCertificateList * chain = NULL;
62    PLArenaPool * arena = NULL;
63    CERTCertListNode * node;
64    int len;
65
66    if (CERT_LIST_EMPTY(list))
67        goto loser;
68
69    arena = PORT_NewArena(4096);
70    if (arena == NULL)
71        goto loser;
72
73    for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
74        len++, node = CERT_LIST_NEXT(node)) {
75    }
76
77    chain = PORT_ArenaNew(arena, CERTCertificateList);
78    if (chain == NULL)
79        goto loser;
80
81    chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
82    if (!chain->certs)
83        goto loser;
84    chain->len = len;
85
86    for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
87        len++, node = CERT_LIST_NEXT(node)) {
88        // Check to see if the last cert to be sent is a self-signed cert,
89        // and if so, omit it from the list of certificates. However, if
90        // there is only one cert (len == 0), include the cert, as it means
91        // the EE cert is self-signed.
92        if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) {
93            chain->len = len;
94            break;
95        }
96        SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
97    }
98
99    chain->arena = arena;
100    return chain;
101
102loser:
103    if (arena) {
104        PORT_FreeArena(arena, PR_FALSE);
105    }
106    return NULL;
107}
108
109#if defined(XP_WIN32)
110typedef SECURITY_STATUS (WINAPI *NCryptFreeObjectFunc)(NCRYPT_HANDLE);
111typedef SECURITY_STATUS (WINAPI *NCryptSignHashFunc)(
112    NCRYPT_KEY_HANDLE /* hKey */,
113    VOID* /* pPaddingInfo */,
114    PBYTE /* pbHashValue */,
115    DWORD /* cbHashValue */,
116    PBYTE /* pbSignature */,
117    DWORD /* cbSignature */,
118    DWORD* /* pcbResult */,
119    DWORD /* dwFlags */);
120
121static PRCallOnceType cngFunctionsInitOnce;
122static const PRCallOnceType pristineCallOnce;
123
124static PRLibrary *ncrypt_library = NULL;
125static NCryptFreeObjectFunc pNCryptFreeObject = NULL;
126static NCryptSignHashFunc pNCryptSignHash = NULL;
127
128static SECStatus
129ssl_ShutdownCngFunctions(void *appData, void *nssData)
130{
131    pNCryptSignHash = NULL;
132    pNCryptFreeObject = NULL;
133    if (ncrypt_library) {
134        PR_UnloadLibrary(ncrypt_library);
135        ncrypt_library = NULL;
136    }
137
138    cngFunctionsInitOnce = pristineCallOnce;
139
140    return SECSuccess;
141}
142
143static PRStatus
144ssl_InitCngFunctions(void)
145{
146    SECStatus rv;
147
148    ncrypt_library = PR_LoadLibrary("ncrypt.dll");
149    if (ncrypt_library == NULL)
150        goto loser;
151
152    pNCryptFreeObject = (NCryptFreeObjectFunc)PR_FindFunctionSymbol(
153        ncrypt_library, "NCryptFreeObject");
154    if (pNCryptFreeObject == NULL)
155        goto loser;
156
157    pNCryptSignHash = (NCryptSignHashFunc)PR_FindFunctionSymbol(
158        ncrypt_library, "NCryptSignHash");
159    if (pNCryptSignHash == NULL)
160        goto loser;
161
162    rv = NSS_RegisterShutdown(ssl_ShutdownCngFunctions, NULL);
163    if (rv != SECSuccess)
164        goto loser;
165
166    return PR_SUCCESS;
167
168loser:
169    pNCryptSignHash = NULL;
170    pNCryptFreeObject = NULL;
171    if (ncrypt_library) {
172        PR_UnloadLibrary(ncrypt_library);
173        ncrypt_library = NULL;
174    }
175
176    return PR_FAILURE;
177}
178
179static SECStatus
180ssl_InitCng(void)
181{
182    if (PR_CallOnce(&cngFunctionsInitOnce, ssl_InitCngFunctions) != PR_SUCCESS)
183        return SECFailure;
184    return SECSuccess;
185}
186
187void
188ssl_FreePlatformKey(PlatformKey key)
189{
190    if (!key)
191        return;
192
193    if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
194        if (ssl_InitCng() == SECSuccess) {
195            (*pNCryptFreeObject)(key->hNCryptKey);
196        }
197    } else {
198        CryptReleaseContext(key->hCryptProv, 0);
199    }
200    PORT_Free(key);
201}
202
203static SECStatus
204ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
205                           PRBool isTLS, KeyType keyType)
206{
207    SECStatus       rv                = SECFailure;
208    SECURITY_STATUS ncrypt_status;
209    PRBool          doDerEncode       = PR_FALSE;
210    SECItem         hashItem;
211    DWORD           signatureLen      = 0;
212    DWORD           dwFlags           = 0;
213    VOID           *pPaddingInfo      = NULL;
214
215    /* Always encode using PKCS#1 block type. */
216    BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo;
217
218    if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) {
219        PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
220        return SECFailure;
221    }
222    if (ssl_InitCng() != SECSuccess) {
223        PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
224        return SECFailure;
225    }
226
227    switch (keyType) {
228        case rsaKey:
229            switch (hash->hashAlg) {
230                case SEC_OID_UNKNOWN:
231                    /* No OID/encoded DigestInfo. */
232                    rsaPaddingInfo.pszAlgId = NULL;
233                    break;
234                case SEC_OID_SHA1:
235                    rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM;
236                    break;
237                case SEC_OID_SHA256:
238                    rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM;
239                    break;
240                case SEC_OID_SHA384:
241                    rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM;
242                    break;
243                case SEC_OID_SHA512:
244                    rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM;
245                    break;
246                default:
247                    PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
248                    return SECFailure;
249            }
250            hashItem.data = hash->u.raw;
251            hashItem.len  = hash->len;
252            dwFlags       = BCRYPT_PAD_PKCS1;
253            pPaddingInfo  = &rsaPaddingInfo;
254            break;
255        case dsaKey:
256        case ecKey:
257            if (keyType == ecKey) {
258                doDerEncode = PR_TRUE;
259            } else {
260                doDerEncode = isTLS;
261            }
262            if (hash->hashAlg == SEC_OID_UNKNOWN) {
263                hashItem.data = hash->u.s.sha;
264                hashItem.len  = sizeof(hash->u.s.sha);
265            } else {
266                hashItem.data = hash->u.raw;
267                hashItem.len  = hash->len;
268            }
269            break;
270        default:
271            PORT_SetError(SEC_ERROR_INVALID_KEY);
272            goto done;
273    }
274    PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
275
276    ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo,
277                                       (PBYTE)hashItem.data, hashItem.len,
278                                       NULL, 0, &signatureLen, dwFlags);
279    if (FAILED(ncrypt_status) || signatureLen == 0) {
280        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status);
281        goto done;
282    }
283
284    buf->data = (unsigned char *)PORT_Alloc(signatureLen);
285    if (!buf->data) {
286        goto done;    /* error code was set. */
287    }
288
289    ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo,
290                                       (PBYTE)hashItem.data, hashItem.len,
291                                       (PBYTE)buf->data, signatureLen,
292                                       &signatureLen, dwFlags);
293    if (FAILED(ncrypt_status) || signatureLen == 0) {
294        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status);
295        goto done;
296    }
297
298    buf->len = signatureLen;
299
300    if (doDerEncode) {
301        SECItem   derSig = {siBuffer, NULL, 0};
302
303        /* This also works for an ECDSA signature */
304        rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
305        if (rv == SECSuccess) {
306            PORT_Free(buf->data);     /* discard unencoded signature. */
307            *buf = derSig;            /* give caller encoded signature. */
308        } else if (derSig.data) {
309            PORT_Free(derSig.data);
310        }
311    } else {
312        rv = SECSuccess;
313    }
314
315    PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
316
317done:
318    if (rv != SECSuccess && buf->data) {
319        PORT_Free(buf->data);
320        buf->data = NULL;
321        buf->len = 0;
322    }
323
324    return rv;
325}
326
327static SECStatus
328ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
329                            PRBool isTLS, KeyType keyType)
330{
331    SECStatus    rv             = SECFailure;
332    PRBool       doDerEncode    = PR_FALSE;
333    SECItem      hashItem;
334    DWORD        argLen         = 0;
335    DWORD        signatureLen   = 0;
336    ALG_ID       hashAlg        = 0;
337    HCRYPTHASH   hHash          = 0;
338    DWORD        hashLen        = 0;
339    unsigned int i              = 0;
340
341    buf->data = NULL;
342
343    switch (hash->hashAlg) {
344        case SEC_OID_UNKNOWN:
345            hashAlg = 0;
346            break;
347        case SEC_OID_SHA1:
348            hashAlg = CALG_SHA1;
349            break;
350        case SEC_OID_SHA256:
351            hashAlg = CALG_SHA_256;
352            break;
353        case SEC_OID_SHA384:
354            hashAlg = CALG_SHA_384;
355            break;
356        case SEC_OID_SHA512:
357            hashAlg = CALG_SHA_512;
358            break;
359        default:
360            PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
361            return SECFailure;
362    }
363
364    switch (keyType) {
365        case rsaKey:
366            if (hashAlg == 0) {
367                hashAlg = CALG_SSL3_SHAMD5;
368            }
369            hashItem.data = hash->u.raw;
370            hashItem.len = hash->len;
371            break;
372        case dsaKey:
373        case ecKey:
374            if (keyType == ecKey) {
375                doDerEncode = PR_TRUE;
376            } else {
377                doDerEncode = isTLS;
378            }
379            if (hashAlg == 0) {
380                hashAlg = CALG_SHA1;
381                hashItem.data = hash->u.s.sha;
382                hashItem.len = sizeof(hash->u.s.sha);
383            } else {
384                hashItem.data = hash->u.raw;
385                hashItem.len = hash->len;
386            }
387            break;
388        default:
389            PORT_SetError(SEC_ERROR_INVALID_KEY);
390            goto done;
391    }
392    PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
393
394    if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) {
395        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
396        goto done;
397    }
398    argLen = sizeof(hashLen);
399    if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) {
400        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
401        goto done;
402    }
403    if (hashLen != hashItem.len) {
404        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, 0);
405        goto done;
406    }
407    if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) {
408        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
409        goto done;
410    }
411    if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
412                       NULL, &signatureLen) || signatureLen == 0) {
413        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
414        goto done;
415    }
416    buf->data = (unsigned char *)PORT_Alloc(signatureLen);
417    if (!buf->data)
418        goto done;    /* error code was set. */
419
420    if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
421                       (BYTE*)buf->data, &signatureLen)) {
422        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError());
423        goto done;
424    }
425    buf->len = signatureLen;
426
427    /* CryptoAPI signs in little-endian, so reverse */
428    for (i = 0; i < buf->len / 2; ++i) {
429        unsigned char tmp = buf->data[i];
430        buf->data[i] = buf->data[buf->len - 1 - i];
431        buf->data[buf->len - 1 - i] = tmp;
432    }
433    if (doDerEncode) {
434        SECItem   derSig = {siBuffer, NULL, 0};
435
436        /* This also works for an ECDSA signature */
437        rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
438        if (rv == SECSuccess) {
439            PORT_Free(buf->data);     /* discard unencoded signature. */
440            *buf = derSig;            /* give caller encoded signature. */
441        } else if (derSig.data) {
442            PORT_Free(derSig.data);
443        }
444    } else {
445        rv = SECSuccess;
446    }
447
448    PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
449done:
450    if (hHash)
451        CryptDestroyHash(hHash);
452    if (rv != SECSuccess && buf->data) {
453        PORT_Free(buf->data);
454        buf->data = NULL;
455    }
456    return rv;
457}
458
459SECStatus
460ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
461                        PRBool isTLS, KeyType keyType)
462{
463    if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) {
464        return ssl3_CngPlatformSignHashes(hash, key, buf, isTLS, keyType);
465    }
466    return ssl3_CAPIPlatformSignHashes(hash, key, buf, isTLS, keyType);
467}
468
469#elif defined(XP_MACOSX)
470#include <Security/cssm.h>
471
472void
473ssl_FreePlatformKey(PlatformKey key)
474{
475    CFRelease(key);
476}
477
478#define SSL_MAX_DIGEST_INFO_PREFIX 20
479
480/* ssl3_GetDigestInfoPrefix sets |out| and |out_len| to point to a buffer that
481 * contains ASN.1 data that should be prepended to a hash of the given type in
482 * order to create a DigestInfo structure that is valid for use in a PKCS #1
483 * v1.5 RSA signature. |out_len| will not be set to a value greater than
484 * SSL_MAX_DIGEST_INFO_PREFIX. */
485static SECStatus
486ssl3_GetDigestInfoPrefix(SECOidTag hashAlg,
487                         const SSL3Opaque** out, unsigned int *out_len)
488{
489    /* These are the DER encoding of ASN.1 DigestInfo structures:
490     *   DigestInfo ::= SEQUENCE {
491     *     digestAlgorithm AlgorithmIdentifier,
492     *     digest OCTET STRING
493     *   }
494     * See PKCS #1 v2.2 Section 9.2, Note 1.
495     */
496    static const unsigned char kSHA1[] = {
497        0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
498        0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
499    };
500    static const unsigned char kSHA224[] = {
501        0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
502        0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
503        0x00, 0x04, 0x1c
504    };
505    static const unsigned char kSHA256[] = {
506        0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
507        0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
508        0x00, 0x04, 0x20
509    };
510    static const unsigned char kSHA384[] = {
511        0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
512        0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
513        0x00, 0x04, 0x30
514    };
515    static const unsigned char kSHA512[] = {
516        0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
517        0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
518        0x00, 0x04, 0x40
519    };
520
521    switch (hashAlg) {
522    case SEC_OID_UNKNOWN:
523        *out_len = 0;
524        break;
525    case SEC_OID_SHA1:
526        *out = kSHA1;
527        *out_len = sizeof(kSHA1);
528        break;
529    case SEC_OID_SHA224:
530        *out = kSHA224;
531        *out_len = sizeof(kSHA224);
532        break;
533    case SEC_OID_SHA256:
534        *out = kSHA256;
535        *out_len = sizeof(kSHA256);
536        break;
537    case SEC_OID_SHA384:
538        *out = kSHA384;
539        *out_len = sizeof(kSHA384);
540        break;
541    case SEC_OID_SHA512:
542        *out = kSHA512;
543        *out_len = sizeof(kSHA512);
544        break;
545    default:
546        PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
547        return SECFailure;
548    }
549
550    return SECSuccess;
551}
552
553/* Given the length of a raw DSA signature (consisting of two integers
554 * r and s), returns the maximum length of the DER encoding of the
555 * following structure:
556 *
557 *    Dss-Sig-Value ::= SEQUENCE {
558 *        r INTEGER,
559 *        s INTEGER
560 *    }
561 */
562static unsigned int
563ssl3_DSAMaxDerEncodedLength(unsigned int rawDsaLen)
564{
565    /* The length of one INTEGER. */
566    unsigned int integerDerLen = rawDsaLen/2 +  /* the integer itself */
567            1 +  /* additional zero byte if high bit is 1 */
568            SEC_ASN1LengthLength(rawDsaLen/2 + 1) +  /* length */
569            1;  /* INTEGER tag */
570
571    /* The length of two INTEGERs in a SEQUENCE */
572    return 2 * integerDerLen +  /* two INTEGERs */
573            SEC_ASN1LengthLength(2 * integerDerLen) +  /* length */
574            1;  /* SEQUENCE tag */
575}
576
577SECStatus
578ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
579                        PRBool isTLS, KeyType keyType)
580{
581    SECStatus       rv                  = SECFailure;
582    PRBool          doDerDecode         = PR_FALSE;
583    unsigned int    rawDsaLen;
584    unsigned int    signatureLen;
585    OSStatus        status              = noErr;
586    CSSM_CSP_HANDLE cspHandle           = 0;
587    const CSSM_KEY *cssmKey             = NULL;
588    CSSM_ALGORITHMS sigAlg;
589    CSSM_ALGORITHMS digestAlg;
590    const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
591    CSSM_RETURN     cssmRv;
592    CSSM_DATA       hashData;
593    CSSM_DATA       signatureData;
594    CSSM_CC_HANDLE  cssmSignature       = 0;
595    const SSL3Opaque* prefix;
596    unsigned int    prefixLen;
597    SSL3Opaque      prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX];
598
599    buf->data = NULL;
600
601    status = SecKeyGetCSPHandle(key, &cspHandle);
602    if (status != noErr) {
603        PORT_SetError(SEC_ERROR_INVALID_KEY);
604        goto done;
605    }
606
607    status = SecKeyGetCSSMKey(key, &cssmKey);
608    if (status != noErr || !cssmKey) {
609        PORT_SetError(SEC_ERROR_NO_KEY);
610        goto done;
611    }
612
613    sigAlg = cssmKey->KeyHeader.AlgorithmId;
614    digestAlg = CSSM_ALGID_NONE;
615
616    switch (keyType) {
617        case rsaKey:
618            PORT_Assert(sigAlg == CSSM_ALGID_RSA);
619            signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
620            if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) !=
621                SECSuccess) {
622                goto done;
623            }
624            if (prefixLen + hash->len > sizeof(prefixAndHash)) {
625                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
626                goto done;
627            }
628            memcpy(prefixAndHash, prefix, prefixLen);
629            memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len);
630            hashData.Data   = prefixAndHash;
631            hashData.Length = prefixLen + hash->len;
632            break;
633        case dsaKey:
634        case ecKey:
635            /* SSL3 DSA signatures are raw, not DER-encoded. CSSM gives back
636             * DER-encoded signatures, so they must be decoded. */
637            doDerDecode = (keyType == dsaKey) && !isTLS;
638
639            /* Compute the maximum size of a DER-encoded signature: */
640            if (keyType == ecKey) {
641                PORT_Assert(sigAlg == CSSM_ALGID_ECDSA);
642                /* LogicalKeySizeInBits is the size of an EC public key. But an
643                 * ECDSA signature length depends on the size of the base
644                 * point's order. For P-256, P-384, and P-521, these two sizes
645                 * are the same. */
646                rawDsaLen =
647                    (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8 * 2;
648            } else {
649                /* TODO(davidben): Get the size of the subprime out of CSSM. For
650                 * now, assume 160; Apple's implementation hardcodes it. */
651                PORT_Assert(sigAlg == CSSM_ALGID_DSA);
652                rawDsaLen = 2 * (160 / 8);
653            }
654            signatureLen = ssl3_DSAMaxDerEncodedLength(rawDsaLen);
655
656            /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated
657             * hash.  In that case, we use just the SHA1 part. */
658            if (hash->hashAlg == SEC_OID_UNKNOWN) {
659                hashData.Data   = hash->u.s.sha;
660                hashData.Length = sizeof(hash->u.s.sha);
661            } else {
662                hashData.Data   = hash->u.raw;
663                hashData.Length = hash->len;
664            }
665            break;
666        default:
667            PORT_SetError(SEC_ERROR_INVALID_KEY);
668            goto done;
669    }
670    PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length));
671
672    if (signatureLen == 0) {
673        PORT_SetError(SEC_ERROR_INVALID_KEY);
674        goto done;
675    }
676
677    buf->data = (unsigned char *)PORT_Alloc(signatureLen);
678    if (!buf->data)
679        goto done;    /* error code was set. */
680
681    /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
682     * you can prevent the UI by setting the provider handle on the
683     * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
684     */
685    status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
686                                  kSecCredentialTypeDefault, &cssmCreds);
687    if (status != noErr) {
688        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status);
689        goto done;
690    }
691
692    signatureData.Length = signatureLen;
693    signatureData.Data   = (uint8*)buf->data;
694
695    cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
696                                             cssmKey, &cssmSignature);
697    if (cssmRv) {
698        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
699        goto done;
700    }
701
702    /* See "Apple Cryptographic Service Provider Functional Specification" */
703    if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
704        /* To set RSA blinding for RSA keys */
705        CSSM_CONTEXT_ATTRIBUTE blindingAttr;
706        blindingAttr.AttributeType   = CSSM_ATTRIBUTE_RSA_BLINDING;
707        blindingAttr.AttributeLength = sizeof(uint32);
708        blindingAttr.Attribute.Uint32 = 1;
709        cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
710        if (cssmRv) {
711            PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
712            goto done;
713        }
714    }
715
716    cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg,
717                           &signatureData);
718    if (cssmRv) {
719        PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv);
720        goto done;
721    }
722    buf->len = signatureData.Length;
723
724    if (doDerDecode) {
725        SECItem* rawSig = DSAU_DecodeDerSigToLen(buf, rawDsaLen);
726        if (rawSig != NULL) {
727            PORT_Free(buf->data);     /* discard encoded signature. */
728            *buf = *rawSig;           /* give caller unencoded signature. */
729            PORT_Free(rawSig);
730            rv = SECSuccess;
731        }
732    } else {
733        rv = SECSuccess;
734    }
735
736    PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
737done:
738    /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
739     * should not be freed. When the PlatformKey is freed, they will be
740     * released.
741     */
742    if (cssmSignature)
743        CSSM_DeleteContext(cssmSignature);
744
745    if (rv != SECSuccess && buf->data) {
746        PORT_Free(buf->data);
747        buf->data = NULL;
748    }
749    return rv;
750}
751#else
752void
753ssl_FreePlatformKey(PlatformKey key)
754{
755}
756
757SECStatus
758ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
759                        PRBool isTLS, KeyType keyType)
760{
761    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
762    return SECFailure;
763}
764#endif
765
766#endif /* NSS_PLATFORM_CLIENT_AUTH */
767