2 * Copyright (c) 1999-2001,2005-2007,2010-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
25 * sslBER.c - BER routines
31 #include "sslMemory.h"
34 #include "sslCrypto.h"
38 #include "appleCdsa.h"
39 #include "SecureTransportPriv.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>
48 /* we should get rid of this low level stuff and use SecAsn1Coder throughout... */
49 #include <security_asn1/secasn1.h>
51 #define SSLBUF_TO_SECITEM(sb, cd) { \
52 (cd)->Length = (sb)->length; \
53 (cd)->Data = (sb)->data; \
57 * Given a PKCS-1 encoded RSA public key, extract the
58 * modulus and public exponent.
60 * RSAPublicKey ::= SEQUENCE {
61 * modulus INTEGER, -- n
62 * publicExponent INTEGER -- e }
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.
71 #define CHUNKSIZE_DEF 1024
73 OSStatus
sslDecodeRsaBlob(
74 const SSLBuffer
*blob
, /* PKCS-1 encoded */
75 SSLBuffer
*modulus
, /* data mallocd and RETURNED */
76 SSLBuffer
*exponent
) /* data mallocd and RETURNED */
80 NSS_RSAPublicKeyPKCS1 nssPubKey
= {};
84 assert(modulus
!= NULL
);
85 assert(exponent
!= NULL
);
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
);
94 /* malloc & copy components */
95 srtn
= SSLCopyBufferFromData(nssPubKey
.modulus
.Data
,
96 nssPubKey
.modulus
.Length
, modulus
);
98 srtn
= SSLCopyBufferFromData(nssPubKey
.publicExponent
.Data
,
99 nssPubKey
.publicExponent
.Length
, exponent
);
102 PORT_FreeArena(pool
, PR_TRUE
);
107 * Given a raw modulus and exponent, cook up a
108 * BER-encoded RSA public key blob.
110 OSStatus
sslEncodeRsaBlob(
111 const SSLBuffer
*modulus
,
112 const SSLBuffer
*exponent
,
113 SSLBuffer
*blob
) /* data mallocd and RETURNED */
117 SECItem
*encBlob
, dest
= {};
118 NSS_RSAPublicKeyPKCS1 nssPubKey
;
120 assert((modulus
!= NULL
) && (exponent
!= NULL
));
122 /* convert to NSS_RSAPublicKeyPKCS1 */
123 SSLBUF_TO_SECITEM(modulus
, &nssPubKey
.modulus
);
124 SSLBUF_TO_SECITEM(exponent
, &nssPubKey
.publicExponent
);
127 pool
= PORT_NewArena(CHUNKSIZE_DEF
);
128 encBlob
= SEC_ASN1EncodeItem(pool
, &dest
, &nssPubKey
,
129 kSecAsn1RSAPublicKeyPKCS1Template
);
131 srtn
= errSecAllocate
;
133 /* copy out to caller */
134 srtn
= SSLCopyBufferFromData(encBlob
->Data
, encBlob
->Length
, blob
);
137 PORT_FreeArena(pool
, PR_TRUE
);
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.
148 OSStatus
sslDecodeDhParams(
149 const SSLBuffer
*blob
, /* PKCS-1 encoded */
150 SSLBuffer
*prime
, /* data mallocd and RETURNED */
151 SSLBuffer
*generator
) /* data mallocd and RETURNED */
155 NSS_DHParameterBlock paramBlock
= {};
158 assert(blob
!= NULL
);
159 assert(prime
!= NULL
);
160 assert(generator
!= NULL
);
162 pool
= PORT_NewArena(CHUNKSIZE_DEF
);
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.
167 rv
= SEC_ASN1Decode(pool
, ¶mBlock
.params
,
168 kSecAsn1DHParameterTemplate
, (const char *)blob
->data
, blob
->length
);
169 if (rv
!= SECSuccess
) {
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.
175 memset(¶mBlock
, 0, sizeof(paramBlock
));
176 rv
= SEC_ASN1Decode(pool
, ¶mBlock
,
177 kSecAsn1DHParameterBlockTemplate
,
178 (const char *)blob
->data
, blob
->length
);
181 if (rv
!= SECSuccess
) {
182 /* Ah well, we tried. */
183 sslErrorLog("sslDecodeDhParams: both CDSA and openssl format"
188 /* copy out components */
189 srtn
= SSLCopyBufferFromData(paramBlock
.params
.prime
.Data
,
190 paramBlock
.params
.prime
.Length
, prime
);
192 srtn
= SSLCopyBufferFromData(paramBlock
.params
.base
.Data
,
193 paramBlock
.params
.base
.Length
, generator
);
197 PORT_FreeArena(pool
, PR_TRUE
);
202 * Given a prime and generator, cook up a BER-encoded DHParameter blob.
204 OSStatus
sslEncodeDhParams(
205 const SSLBuffer
*prime
,
206 const SSLBuffer
*generator
,
207 SSLBuffer
*blob
) /* data mallocd and RETURNED */
211 SECItem
*encBlob
, dest
= {};
212 NSS_DHParameter dhParams
;
214 assert((prime
!= NULL
) && (generator
!= NULL
));
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;
223 pool
= PORT_NewArena(CHUNKSIZE_DEF
);
224 encBlob
= SEC_ASN1EncodeItem(pool
, &dest
, &dhParams
,
225 kSecAsn1DHParameterTemplate
);
227 srtn
= errSecAllocate
;
229 /* copy out to caller */
230 srtn
= SSLCopyBufferFromData(encBlob
->Data
, encBlob
->Length
, blob
);
233 PORT_FreeArena(pool
, PR_TRUE
);
236 #endif /* APPLE_DH */
239 * Given an ECDSA key in CSSM format, extract the SSL_ECDSA_NamedCurve
240 * from its algorithm parameters.
242 OSStatus
sslEcdsaPeerCurve(
244 SSL_ECDSA_NamedCurve
*namedCurve
)
246 SecAsn1CoderRef coder
= NULL
;
247 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo
;
248 CSSM_X509_ALGORITHM_IDENTIFIER
*algId
= &subjPubKeyInfo
.algorithm
;
252 CSSM_KEYHEADER
*hdr
= &pubKey
->KeyHeader
;
253 if(hdr
->AlgorithmId
!= CSSM_ALGID_ECDSA
) {
254 sslErrorLog("sslEcdsaPeerCurve: bad peer key algorithm\n");
255 return errSSLProtocol
;
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
;
262 if(hdr
->Format
!= CSSM_KEYBLOB_RAW_FORMAT_X509
) {
263 sslErrorLog("sslEcdsaPeerCurve: bad peer key format\n");
264 return errSSLProtocol
;
267 /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
268 ortn
= SecAsn1CoderCreate(&coder
);
270 return errSSLInternal
;
272 /* subsequent errors to errOut: */
274 memset(&subjPubKeyInfo
, 0, sizeof(subjPubKeyInfo
));
275 ortn
= SecAsn1DecodeData(coder
, &pubKey
->KeyData
, kSecAsn1SubjectPublicKeyInfoTemplate
,
278 printf("sslEcdsaPeerCurve: error decoding public key\n");
282 if(!nssCompareCssmData(&algId
->algorithm
, &CSSMOID_ecPublicKey
)) {
283 printf("sslEcdsaPeerCurve: unexpected algorithm ID in public key\n");
284 ortn
= errSSLProtocol
;
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
;
295 * The curve OID is DER-encoded since the parameters are ASN_ANY.
296 * Quickie decode for further processing...
298 curveOid
.Data
= algId
->parameters
.Data
+ 2;
299 curveOid
.Length
= algId
->parameters
.Length
- 2;
301 /* algId->parameters is the curve OID */
302 if(nssCompareCssmData(&curveOid
, &CSSMOID_secp256r1
)) {
303 *namedCurve
= SSL_Curve_secp256r1
;
305 else if(nssCompareCssmData(&curveOid
, &CSSMOID_secp384r1
)) {
306 *namedCurve
= SSL_Curve_secp384r1
;
308 else if(nssCompareCssmData(&curveOid
, &CSSMOID_secp521r1
)) {
309 *namedCurve
= SSL_Curve_secp521r1
;
311 /* Others? Later. That's all we support for now. */
313 printf("sslEcdsaPeerCurve: missing algorithm parameters in public key\n");
314 ortn
= errSSLProtocol
;
318 SecAsn1CoderRelease(coder
);
323 * Given an ECDSA public key in X509 format, extract the raw public key
324 * bits in ECPOint format.
326 OSStatus
sslEcdsaPubKeyBits(
328 SSLBuffer
*pubBits
) /* data mallocd and RETURNED */
330 SecAsn1CoderRef coder
= NULL
;
331 CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo
;
332 OSStatus ortn
= errSecSuccess
;
334 CSSM_KEYHEADER
*hdr
= &pubKey
->KeyHeader
;
335 if(hdr
->AlgorithmId
!= CSSM_ALGID_ECDSA
) {
336 sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n");
337 return errSSLProtocol
;
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
;
344 if(hdr
->Format
!= CSSM_KEYBLOB_RAW_FORMAT_X509
) {
345 sslErrorLog("sslEcdsaPubKeyBits: bad peer key format\n");
346 return errSSLProtocol
;
349 /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */
350 ortn
= SecAsn1CoderCreate(&coder
);
352 return errSSLInternal
;
354 /* subsequent errors to errOut: */
356 memset(&subjPubKeyInfo
, 0, sizeof(subjPubKeyInfo
));
357 ortn
= SecAsn1DecodeData(coder
, &pubKey
->KeyData
, kSecAsn1SubjectPublicKeyInfoTemplate
,
360 printf("sslEcdsaPubKeyBits: error decoding public key\n");
363 /* that key data is a BITSTRING */
364 ortn
= SSLCopyBufferFromData(subjPubKeyInfo
.subjectPublicKey
.Data
,
365 subjPubKeyInfo
.subjectPublicKey
.Length
>> 3, pubBits
);
367 SecAsn1CoderRelease(coder
);
371 #endif /* USE_CDSA_CRYPTO */