]> git.saurik.com Git - apple/security.git/blob - Security/libsecurity_ssl/lib/sslBER.c
Security-57031.40.6.tar.gz
[apple/security.git] / Security / libsecurity_ssl / lib / sslBER.c
1 /*
2 * Copyright (c) 1999-2001,2005-2007,2010-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * sslBER.c - BER routines
26 */
27
28 #if USE_CDSA_CRYPTO
29
30 #include "ssl.h"
31 #include "sslMemory.h"
32 #include "sslDebug.h"
33 #include "sslBER.h"
34 #include "sslCrypto.h"
35
36 #include <string.h>
37
38 #include "appleCdsa.h"
39 #include "SecureTransportPriv.h"
40
41 #include <string.h>
42 #include <Security/SecAsn1Coder.h>
43 #include <Security/keyTemplates.h>
44 #include <security_asn1/nssUtils.h>
45 #include <Security/oidsattr.h>
46 #include <Security/oidsalg.h>
47
48 /* we should get rid of this low level stuff and use SecAsn1Coder throughout... */
49 #include <security_asn1/secasn1.h>
50
51 #define SSLBUF_TO_SECITEM(sb, cd) { \
52 (cd)->Length = (sb)->length; \
53 (cd)->Data = (sb)->data; \
54 }
55
56 /*
57 * Given a PKCS-1 encoded RSA public key, extract the
58 * modulus and public exponent.
59 *
60 * RSAPublicKey ::= SEQUENCE {
61 * modulus INTEGER, -- n
62 * publicExponent INTEGER -- e }
63 */
64
65 /*
66 * Default chunk size for new arena pool.
67 * FIXME: analyze & measure different defaults here. I'm pretty sure
68 * that only performance - not correct behavior - is affected by
69 * an arena pool's chunk size.
70 */
71 #define CHUNKSIZE_DEF 1024
72
73 OSStatus sslDecodeRsaBlob(
74 const SSLBuffer *blob, /* PKCS-1 encoded */
75 SSLBuffer *modulus, /* data mallocd and RETURNED */
76 SSLBuffer *exponent) /* data mallocd and RETURNED */
77 {
78 SECStatus rv;
79 OSStatus srtn;
80 NSS_RSAPublicKeyPKCS1 nssPubKey = {};
81 PLArenaPool *pool;
82
83 assert(blob != NULL);
84 assert(modulus != NULL);
85 assert(exponent != NULL);
86
87 /* DER-decode the blob */
88 pool = PORT_NewArena(CHUNKSIZE_DEF);
89 rv = SEC_ASN1Decode(pool, &nssPubKey,
90 kSecAsn1RSAPublicKeyPKCS1Template, (const char *)blob->data, blob->length);
91 if (rv != SECSuccess)
92 srtn = errSSLBadCert;
93 else {
94 /* malloc & copy components */
95 srtn = SSLCopyBufferFromData(nssPubKey.modulus.Data,
96 nssPubKey.modulus.Length, modulus);
97 if(!srtn) {
98 srtn = SSLCopyBufferFromData(nssPubKey.publicExponent.Data,
99 nssPubKey.publicExponent.Length, exponent);
100 }
101 }
102 PORT_FreeArena(pool, PR_TRUE);
103 return srtn;
104 }
105
106 /*
107 * Given a raw modulus and exponent, cook up a
108 * BER-encoded RSA public key blob.
109 */
110 OSStatus sslEncodeRsaBlob(
111 const SSLBuffer *modulus,
112 const SSLBuffer *exponent,
113 SSLBuffer *blob) /* data mallocd and RETURNED */
114 {
115 PLArenaPool *pool;
116 OSStatus srtn;
117 SECItem *encBlob, dest = {};
118 NSS_RSAPublicKeyPKCS1 nssPubKey;
119
120 assert((modulus != NULL) && (exponent != NULL));
121
122 /* convert to NSS_RSAPublicKeyPKCS1 */
123 SSLBUF_TO_SECITEM(modulus, &nssPubKey.modulus);
124 SSLBUF_TO_SECITEM(exponent, &nssPubKey.publicExponent);
125
126 /* DER encode */
127 pool = PORT_NewArena(CHUNKSIZE_DEF);
128 encBlob = SEC_ASN1EncodeItem(pool, &dest, &nssPubKey,
129 kSecAsn1RSAPublicKeyPKCS1Template);
130 if (!encBlob)
131 srtn = errSecAllocate;
132 else {
133 /* copy out to caller */
134 srtn = SSLCopyBufferFromData(encBlob->Data, encBlob->Length, blob);
135 }
136
137 PORT_FreeArena(pool, PR_TRUE);
138 return srtn;
139 }
140
141 #if APPLE_DH
142 /*
143 * Given a DER encoded DHParameterBlock, extract the prime and generator.
144 * modulus and public exponent.
145 * This will work with either PKCS-1 encoded DHParameterBlock or
146 * openssl-style DHParameter.
147 */
148 OSStatus sslDecodeDhParams(
149 const SSLBuffer *blob, /* PKCS-1 encoded */
150 SSLBuffer *prime, /* data mallocd and RETURNED */
151 SSLBuffer *generator) /* data mallocd and RETURNED */
152 {
153 SECStatus rv;
154 OSStatus srtn;
155 NSS_DHParameterBlock paramBlock = {};
156 PLArenaPool *pool;
157
158 assert(blob != NULL);
159 assert(prime != NULL);
160 assert(generator != NULL);
161
162 pool = PORT_NewArena(CHUNKSIZE_DEF);
163 /*
164 * Since the common case here is to decode a parameter block coming
165 * over the wire, which is in openssl format, let's try that format first.
166 */
167 rv = SEC_ASN1Decode(pool, &paramBlock.params,
168 kSecAsn1DHParameterTemplate, (const char *)blob->data, blob->length);
169 if (rv != SECSuccess) {
170 /*
171 * OK, that failed when trying as a CDSA_formatted parameter
172 * block DHParameterBlock). Openssl uses a subset of that,
173 * a DHParameter. Try that instead.
174 */
175 memset(&paramBlock, 0, sizeof(paramBlock));
176 rv = SEC_ASN1Decode(pool, &paramBlock,
177 kSecAsn1DHParameterBlockTemplate,
178 (const char *)blob->data, blob->length);
179 }
180
181 if (rv != SECSuccess) {
182 /* Ah well, we tried. */
183 sslErrorLog("sslDecodeDhParams: both CDSA and openssl format"
184 "failed\n");
185 srtn = errSSLCrypto;
186 }
187 else {
188 /* copy out components */
189 srtn = SSLCopyBufferFromData(paramBlock.params.prime.Data,
190 paramBlock.params.prime.Length, prime);
191 if(!srtn) {
192 srtn = SSLCopyBufferFromData(paramBlock.params.base.Data,
193 paramBlock.params.base.Length, generator);
194 }
195 }
196
197 PORT_FreeArena(pool, PR_TRUE);
198 return srtn;
199 }
200
201 /*
202 * Given a prime and generator, cook up a BER-encoded DHParameter blob.
203 */
204 OSStatus sslEncodeDhParams(
205 const SSLBuffer *prime,
206 const SSLBuffer *generator,
207 SSLBuffer *blob) /* data mallocd and RETURNED */
208 {
209 PLArenaPool *pool;
210 OSStatus srtn;
211 SECItem *encBlob, dest = {};
212 NSS_DHParameter dhParams;
213
214 assert((prime != NULL) && (generator != NULL));
215
216 /* convert to NSS_DHParameter */
217 SSLBUF_TO_SECITEM(prime, &dhParams.prime);
218 SSLBUF_TO_SECITEM(generator, &dhParams.base);
219 dhParams.privateValueLength.Data = NULL;
220 dhParams.privateValueLength.Length = 0;
221
222 /* DER encode */
223 pool = PORT_NewArena(CHUNKSIZE_DEF);
224 encBlob = SEC_ASN1EncodeItem(pool, &dest, &dhParams,
225 kSecAsn1DHParameterTemplate);
226 if (!encBlob)
227 srtn = errSecAllocate;
228 else {
229 /* copy out to caller */
230 srtn = SSLCopyBufferFromData(encBlob->Data, encBlob->Length, blob);
231 }
232
233 PORT_FreeArena(pool, PR_TRUE);
234 return srtn;
235 }
236 #endif /* APPLE_DH */
237
238 /*
239 * Given an ECDSA key in CSSM format, extract the SSL_ECDSA_NamedCurve
240 * from its algorithm parameters.
241 */
242 OSStatus sslEcdsaPeerCurve(
243 CSSM_KEY_PTR pubKey,
244 SSL_ECDSA_NamedCurve *namedCurve)
245 {
246 SecAsn1CoderRef coder = NULL;
247 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo;
248 CSSM_X509_ALGORITHM_IDENTIFIER *algId = &subjPubKeyInfo.algorithm;
249 CSSM_OID curveOid;
250 OSStatus ortn;
251
252 CSSM_KEYHEADER *hdr = &pubKey->KeyHeader;
253 if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) {
254 sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n");
255 return errSSLProtocol;
256 }
257 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
258 /* No can do - this must be raw format, it came from the CL */
259 sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n");
260 return errSSLProtocol;
261 }
262 if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
263 sslErrorLog("sslEcdsaPeerCurve: bad peer key format\n");
264 return errSSLProtocol;
265 }
266
267 /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
268 ortn = SecAsn1CoderCreate(&coder);
269 if(ortn) {
270 return errSSLInternal;
271 }
272 /* subsequent errors to errOut: */
273
274 memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo));
275 ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate,
276 &subjPubKeyInfo);
277 if(ortn) {
278 printf("sslEcdsaPeerCurve: error decoding public key\n");
279 goto errOut;
280 }
281
282 if(!nssCompareCssmData(&algId->algorithm, &CSSMOID_ecPublicKey)) {
283 printf("sslEcdsaPeerCurve: unexpected algorithm ID in public key\n");
284 ortn = errSSLProtocol;
285 goto errOut;
286 }
287 if((algId->parameters.Data[0] != BER_TAG_OID) ||
288 (algId->parameters.Length < 2)) {
289 printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n");
290 ortn = errSSLProtocol;
291 goto errOut;
292 }
293
294 /*
295 * The curve OID is DER-encoded since the parameters are ASN_ANY.
296 * Quickie decode for further processing...
297 */
298 curveOid.Data = algId->parameters.Data + 2;
299 curveOid.Length = algId->parameters.Length - 2;
300
301 /* algId->parameters is the curve OID */
302 if(nssCompareCssmData(&curveOid, &CSSMOID_secp256r1)) {
303 *namedCurve = SSL_Curve_secp256r1;
304 }
305 else if(nssCompareCssmData(&curveOid, &CSSMOID_secp384r1)) {
306 *namedCurve = SSL_Curve_secp384r1;
307 }
308 else if(nssCompareCssmData(&curveOid, &CSSMOID_secp521r1)) {
309 *namedCurve = SSL_Curve_secp521r1;
310 }
311 /* Others? Later. That's all we support for now. */
312 else {
313 printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n");
314 ortn = errSSLProtocol;
315 }
316
317 errOut:
318 SecAsn1CoderRelease(coder);
319 return ortn;
320 }
321
322 /*
323 * Given an ECDSA public key in X509 format, extract the raw public key
324 * bits in ECPOint format.
325 */
326 OSStatus sslEcdsaPubKeyBits(
327 CSSM_KEY_PTR pubKey,
328 SSLBuffer *pubBits) /* data mallocd and RETURNED */
329 {
330 SecAsn1CoderRef coder = NULL;
331 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo;
332 OSStatus ortn = errSecSuccess;
333
334 CSSM_KEYHEADER *hdr = &pubKey->KeyHeader;
335 if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) {
336 sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n");
337 return errSSLProtocol;
338 }
339 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
340 /* No can do - this must be raw format, it came from the CL */
341 sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n");
342 return errSSLProtocol;
343 }
344 if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) {
345 sslErrorLog("sslEcdsaPubKeyBits: bad peer key format\n");
346 return errSSLProtocol;
347 }
348
349 /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
350 ortn = SecAsn1CoderCreate(&coder);
351 if(ortn) {
352 return errSSLInternal;
353 }
354 /* subsequent errors to errOut: */
355
356 memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo));
357 ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate,
358 &subjPubKeyInfo);
359 if(ortn) {
360 printf("sslEcdsaPubKeyBits: error decoding public key\n");
361 goto errOut;
362 }
363 /* that key data is a BITSTRING */
364 ortn = SSLCopyBufferFromData(subjPubKeyInfo.subjectPublicKey.Data,
365 subjPubKeyInfo.subjectPublicKey.Length >> 3, pubBits);
366 errOut:
367 SecAsn1CoderRelease(coder);
368 return ortn;
369 }
370
371 #endif /* USE_CDSA_CRYPTO */