Revert "Merged all Chromoting Host code into remoting_core.dll (Windows)."
[chromium-blink-merge.git] / net / third_party / nss / ssl / sslplatf.c
blob208956f8912a4664dec112bf1b5b98c57844cc2f
1 /*
2 * Platform specific crypto wrappers
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is the Netscape security libraries.
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.
24 * Contributor(s):
25 * Ryan Sleevi <ryan.sleevi@gmail.com>
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.
39 * ***** END LICENSE BLOCK ***** */
40 /* $Id$ */
41 #include "ssl.h"
42 #include "certt.h"
43 #include "keythi.h"
44 #include "sslimpl.h"
45 #include "cryptohi.h"
46 #include "secitem.h"
48 #ifdef NSS_PLATFORM_CLIENT_AUTH
49 CERTCertificateList*
50 hack_NewCertificateListFromCertList(CERTCertList* list)
52 CERTCertificateList * chain = NULL;
53 PRArenaPool * arena = NULL;
54 CERTCertListNode * node;
55 int len;
57 if (CERT_LIST_EMPTY(list))
58 goto loser;
60 arena = PORT_NewArena(4096);
61 if (arena == NULL)
62 goto loser;
64 for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
65 len++, node = CERT_LIST_NEXT(node)) {
68 chain = PORT_ArenaNew(arena, CERTCertificateList);
69 if (chain == NULL)
70 goto loser;
72 chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
73 if (!chain->certs)
74 goto loser;
75 chain->len = len;
77 for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
78 len++, node = CERT_LIST_NEXT(node)) {
79 // Check to see if the last cert to be sent is a self-signed cert,
80 // and if so, omit it from the list of certificates. However, if
81 // there is only one cert (len == 0), include the cert, as it means
82 // the EE cert is self-signed.
83 if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) {
84 chain->len = len;
85 break;
87 SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
90 chain->arena = arena;
91 return chain;
93 loser:
94 if (arena) {
95 PORT_FreeArena(arena, PR_FALSE);
97 return NULL;
100 #if defined(XP_WIN32)
101 void
102 ssl_FreePlatformKey(PlatformKey key)
104 if (key) {
105 if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC)
106 CryptReleaseContext(key->hCryptProv, 0);
107 /* FIXME(rsleevi): Close CNG keys. */
108 PORT_Free(key);
112 SECStatus
113 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
114 PRBool isTLS)
116 SECStatus rv = SECFailure;
117 PRBool doDerEncode = PR_FALSE;
118 SECItem hashItem;
119 HCRYPTKEY hKey = 0;
120 DWORD argLen = 0;
121 ALG_ID keyAlg = 0;
122 DWORD signatureLen = 0;
123 ALG_ID hashAlg = 0;
124 HCRYPTHASH hHash = 0;
125 DWORD hashLen = 0;
126 unsigned int i = 0;
128 buf->data = NULL;
129 if (!CryptGetUserKey(key->hCryptProv, key->dwKeySpec, &hKey)) {
130 if (GetLastError() == NTE_NO_KEY) {
131 PORT_SetError(SEC_ERROR_NO_KEY);
132 } else {
133 PORT_SetError(SEC_ERROR_INVALID_KEY);
135 goto done;
138 argLen = sizeof(keyAlg);
139 if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&keyAlg, &argLen, 0)) {
140 PORT_SetError(SEC_ERROR_INVALID_KEY);
141 goto done;
144 switch (keyAlg) {
145 case CALG_RSA_KEYX:
146 case CALG_RSA_SIGN:
147 hashAlg = CALG_SSL3_SHAMD5;
148 hashItem.data = hash->md5;
149 hashItem.len = sizeof(SSL3Hashes);
150 break;
151 case CALG_DSS_SIGN:
152 case CALG_ECDSA:
153 if (keyAlg == CALG_ECDSA) {
154 doDerEncode = PR_TRUE;
155 } else {
156 doDerEncode = isTLS;
158 hashAlg = CALG_SHA1;
159 hashItem.data = hash->sha;
160 hashItem.len = sizeof(hash->sha);
161 break;
162 default:
163 PORT_SetError(SEC_ERROR_INVALID_KEY);
164 goto done;
166 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
168 if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) {
169 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
170 goto done;
172 argLen = sizeof(hashLen);
173 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) {
174 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
175 goto done;
177 if (hashLen != hashItem.len) {
178 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
179 goto done;
181 if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) {
182 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
183 goto done;
185 if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
186 NULL, &signatureLen) || signatureLen == 0) {
187 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
188 goto done;
190 buf->data = (unsigned char *)PORT_Alloc(signatureLen);
191 if (!buf->data)
192 goto done; /* error code was set. */
194 if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0,
195 (BYTE*)buf->data, &signatureLen)) {
196 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
197 goto done;
199 buf->len = signatureLen;
201 /* CryptoAPI signs in little-endian, so reverse */
202 for (i = 0; i < buf->len / 2; ++i) {
203 unsigned char tmp = buf->data[i];
204 buf->data[i] = buf->data[buf->len - 1 - i];
205 buf->data[buf->len - 1 - i] = tmp;
207 if (doDerEncode) {
208 SECItem derSig = {siBuffer, NULL, 0};
210 /* This also works for an ECDSA signature */
211 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
212 if (rv == SECSuccess) {
213 PORT_Free(buf->data); /* discard unencoded signature. */
214 *buf = derSig; /* give caller encoded signature. */
215 } else if (derSig.data) {
216 PORT_Free(derSig.data);
218 } else {
219 rv = SECSuccess;
222 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
223 done:
224 if (hHash)
225 CryptDestroyHash(hHash);
226 if (hKey)
227 CryptDestroyKey(hKey);
228 if (rv != SECSuccess && buf->data) {
229 PORT_Free(buf->data);
230 buf->data = NULL;
232 return rv;
235 #elif defined(XP_MACOSX)
236 #include <Security/cssm.h>
238 void
239 ssl_FreePlatformKey(PlatformKey key)
241 CFRelease(key);
244 SECStatus
245 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
246 PRBool isTLS)
248 SECStatus rv = SECFailure;
249 PRBool doDerEncode = PR_FALSE;
250 unsigned int signatureLen;
251 OSStatus status = noErr;
252 CSSM_CSP_HANDLE cspHandle = 0;
253 const CSSM_KEY *cssmKey = NULL;
254 CSSM_ALGORITHMS sigAlg;
255 const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
256 CSSM_RETURN cssmRv;
257 CSSM_DATA hashData;
258 CSSM_DATA signatureData;
259 CSSM_CC_HANDLE cssmSignature = 0;
261 buf->data = NULL;
263 status = SecKeyGetCSPHandle(key, &cspHandle);
264 if (status != noErr) {
265 PORT_SetError(SEC_ERROR_INVALID_KEY);
266 goto done;
269 status = SecKeyGetCSSMKey(key, &cssmKey);
270 if (status != noErr || !cssmKey) {
271 PORT_SetError(SEC_ERROR_NO_KEY);
272 goto done;
275 /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
276 * needed information is readily available on the key itself.
278 signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
280 if (signatureLen == 0) {
281 PORT_SetError(SEC_ERROR_INVALID_KEY);
282 goto done;
285 buf->data = (unsigned char *)PORT_Alloc(signatureLen);
286 if (!buf->data)
287 goto done; /* error code was set. */
289 sigAlg = cssmKey->KeyHeader.AlgorithmId;
290 switch (sigAlg) {
291 case CSSM_ALGID_RSA:
292 hashData.Data = hash->md5;
293 hashData.Length = sizeof(SSL3Hashes);
294 break;
295 case CSSM_ALGID_ECDSA:
296 case CSSM_ALGID_DSA:
297 if (sigAlg == CSSM_ALGID_ECDSA) {
298 doDerEncode = PR_TRUE;
299 } else {
300 doDerEncode = isTLS;
302 hashData.Data = hash->sha;
303 hashData.Length = sizeof(hash->sha);
304 break;
305 default:
306 PORT_SetError(SEC_ERROR_INVALID_KEY);
307 goto done;
309 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length));
311 /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
312 * you can prevent the UI by setting the provider handle on the
313 * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
315 status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
316 kSecCredentialTypeDefault, &cssmCreds);
317 if (status != noErr) {
318 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
319 goto done;
322 signatureData.Length = signatureLen;
323 signatureData.Data = (uint8*)buf->data;
325 cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
326 cssmKey, &cssmSignature);
327 if (cssmRv) {
328 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
329 goto done;
332 /* See "Apple Cryptographic Service Provider Functional Specification" */
333 if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
334 /* To set RSA blinding for RSA keys */
335 CSSM_CONTEXT_ATTRIBUTE blindingAttr;
336 blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
337 blindingAttr.AttributeLength = sizeof(uint32);
338 blindingAttr.Attribute.Uint32 = 1;
339 cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
340 if (cssmRv) {
341 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
342 goto done;
346 cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE,
347 &signatureData);
348 if (cssmRv) {
349 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE);
350 goto done;
352 buf->len = signatureData.Length;
354 if (doDerEncode) {
355 SECItem derSig = {siBuffer, NULL, 0};
357 /* This also works for an ECDSA signature */
358 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
359 if (rv == SECSuccess) {
360 PORT_Free(buf->data); /* discard unencoded signature. */
361 *buf = derSig; /* give caller encoded signature. */
362 } else if (derSig.data) {
363 PORT_Free(derSig.data);
365 } else {
366 rv = SECSuccess;
369 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
370 done:
371 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
372 * should not be freed. When the PlatformKey is freed, they will be
373 * released.
375 if (cssmSignature)
376 CSSM_DeleteContext(cssmSignature);
378 if (rv != SECSuccess && buf->data) {
379 PORT_Free(buf->data);
380 buf->data = NULL;
382 return rv;
384 #else
385 void
386 ssl_FreePlatformKey(PlatformKey key)
390 SECStatus
391 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
392 PRBool isTLS)
394 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
395 return SECFailure;
397 #endif
399 #endif /* NSS_PLATFORM_CLIENT_AUTH */