2 * Copyright (c) 2006-2012 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 * sslCrypto.c - interface between SSL and crypto libraries
28 #include "sslCrypto.h"
30 #include "CipherSuite.h"
32 #include "sslContext.h"
33 #include "sslMemory.h"
36 #include <libDER/DER_CertCrl.h>
37 #include <libDER/DER_Keys.h>
38 #include <CoreFoundation/CFString.h>
39 #include <Security/SecKey.h>
40 #include <Security/SecKeyPriv.h>
41 #include <Security/SecKeyInternal.h>
42 #include <corecrypto/ccdh.h>
43 #include <corecrypto/ccec.h>
44 #include <corecrypto/ccrng.h>
45 #include <Security/SecCertificate.h>
46 #include <Security/SecPolicy.h>
47 #include <Security/SecRSAKey.h>
48 #include <Security/SecTrust.h>
49 #include <AssertMacros.h>
50 #include <Security/SecInternal.h>
52 #ifndef _SSL_KEYCHAIN_H_
53 #include "sslKeychain.h"
57 #include <libDER/libDER.h>
58 #include <libDER/DER_Keys.h>
59 #include <libDER/DER_Encode.h>
60 #include <libDER/asn1Types.h>
61 #include <Security/SecRandom.h>
63 #include <Security/SecECKey.h>
70 #define CCRNGSTATE ccrng_seckey
72 /* extern struct ccrng_state *ccDRBGGetRngState(); */
73 #include <CommonCrypto/CommonRandomSPI.h>
74 #define CCRNGSTATE ccDRBGGetRngState()
79 * Free a pubKey object.
81 extern OSStatus
sslFreePubKey(SSLPubKey
**pubKey
)
83 if (pubKey
&& *pubKey
) {
84 CFReleaseNull(SECKEYREF(*pubKey
));
90 * Free a privKey object.
92 extern OSStatus
sslFreePrivKey(SSLPrivKey
**privKey
)
94 if (privKey
&& *privKey
) {
95 CFReleaseNull(SECKEYREF(*privKey
));
101 * Get algorithm id for a SSLPubKey object.
103 CFIndex
sslPubKeyGetAlgorithmID(SSLPubKey
*pubKey
)
106 return SecKeyGetAlgorithmID(SECKEYREF(pubKey
));
108 return SecKeyGetAlgorithmId(SECKEYREF(pubKey
));
113 * Get algorithm id for a SSLPrivKey object.
115 CFIndex
sslPrivKeyGetAlgorithmID(SSLPrivKey
*privKey
)
118 return SecKeyGetAlgorithmID(SECKEYREF(privKey
));
120 return SecKeyGetAlgorithmId(SECKEYREF(privKey
));
125 * Raw RSA/DSA sign/verify.
130 const uint8_t *plainText
,
132 uint8_t *sig
, // mallocd by caller; RETURNED
133 size_t sigLen
, // available
134 size_t *actualBytes
) // RETURNED
138 #if RSA_SIG_SHARE_GIANT
139 RSASignBuffer
*signBuffer
= (RSASignBuffer
*)sig
;
140 assert(sigLen
>= sizeof(RSASignBuffer
));
142 assert(actualBytes
!= NULL
);
144 /* @@@ Shouldn't need to init giSigLen according to libgRSA docs. */
145 gi_uint16 giSigLen
= sigLen
;
147 rsaStatus
= RSA_Sign(&privKey
->rsaKey
,
151 #if RSA_SIG_SHARE_GIANT
157 *actualBytes
= giSigLen
;
159 return rsaStatus
? rsaStatusToSSL(rsaStatus
) : noErr
;
162 size_t inOutSigLen
= sigLen
;
164 assert(actualBytes
!= NULL
);
166 OSStatus status
= SecKeyRawSign(SECKEYREF(privKey
), kSecPaddingPKCS1
,
167 plainText
, plainTextLen
, sig
, &inOutSigLen
);
170 sslErrorLog("sslRawSign: SecKeyRawSign failed (error %d)\n", status
);
173 /* Since the KeyExchange already allocated modulus size bytes we'll
174 use all of them. SecureTransport has always sent that many bytes,
175 so we're not going to deviate, to avoid interoperability issues. */
176 if (!status
&& (inOutSigLen
< sigLen
)) {
177 size_t offset
= sigLen
- inOutSigLen
;
178 memmove(sig
+ offset
, sig
, inOutSigLen
);
179 memset(sig
, 0, offset
);
180 inOutSigLen
= sigLen
;
184 *actualBytes
= inOutSigLen
;
189 /* TLS 1.2 RSA signature */
193 const SecAsn1AlgId
*algId
,
194 const uint8_t *plainText
,
196 uint8_t *sig
, // mallocd by caller; RETURNED
197 size_t sigLen
, // available
198 size_t *actualBytes
) // RETURNED
200 size_t inOutSigLen
= sigLen
;
202 assert(actualBytes
!= NULL
);
204 OSStatus status
= SecKeySignDigest(SECKEYREF(privKey
), algId
,
205 plainText
, plainTextLen
, sig
, &inOutSigLen
);
208 sslErrorLog("sslRsaSign: SecKeySignDigest failed (error %d)\n", status
);
211 /* Since the KeyExchange already allocated modulus size bytes we'll
212 use all of them. SecureTransport has always sent that many bytes,
213 so we're not going to deviate, to avoid interoperability issues. */
214 if (!status
&& (inOutSigLen
< sigLen
)) {
215 size_t offset
= sigLen
- inOutSigLen
;
216 memmove(sig
+ offset
, sig
, inOutSigLen
);
217 memset(sig
, 0, offset
);
218 inOutSigLen
= sigLen
;
221 *actualBytes
= inOutSigLen
;
225 OSStatus
sslRawVerify(
228 const uint8_t *plainText
,
231 size_t sigLen
) // available
236 rsaStatus
= RSA_SigVerify(&pubKey
->rsaKey
,
243 return rsaStatus
? rsaStatusToSSL(rsaStatus
) : noErr
;
245 OSStatus status
= SecKeyRawVerify(SECKEYREF(pubKey
), kSecPaddingPKCS1
,
246 plainText
, plainTextLen
, sig
, sigLen
);
249 sslErrorLog("sslRawVerify: SecKeyRawVerify failed (error %d)\n", status
);
256 /* TLS 1.2 RSA verify */
257 OSStatus
sslRsaVerify(
260 const SecAsn1AlgId
*algId
,
261 const uint8_t *plainText
,
264 size_t sigLen
) // available
266 OSStatus status
= SecKeyVerifyDigest(SECKEYREF(pubKey
), algId
,
267 plainText
, plainTextLen
, sig
, sigLen
);
270 sslErrorLog("sslRsaVerify: SecKeyVerifyDigest failed (error %d)\n", status
);
279 OSStatus
sslRsaEncrypt(
282 const uint32_t padding
,
283 const uint8_t *plainText
,
285 uint8_t *cipherText
, // mallocd by caller; RETURNED
286 size_t cipherTextLen
, // available
287 size_t *actualBytes
) // RETURNED
290 gi_uint16 giCipherTextLen
= cipherTextLen
;
293 assert(actualBytes
!= NULL
);
295 rsaStatus
= RSA_Encrypt(&pubKey
->rsaKey
,
302 *actualBytes
= giCipherTextLen
;
304 return rsaStatus
? rsaStatusToSSL(rsaStatus
) : noErr
;
306 size_t ctlen
= cipherTextLen
;
308 assert(actualBytes
!= NULL
);
310 #if RSA_PUB_KEY_USAGE_HACK
311 /* Force key usage to allow encryption with public key */
312 #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
313 const CSSM_KEY_PTR cssmKey
= NULL
;
314 if (SecKeyGetCSSMKey(SECKEYREF(pubKey
), &cssmKey
)==noErr
&& cssmKey
)
315 cssmKey
->KeyHeader
.KeyUsage
|= CSSM_KEYUSE_ENCRYPT
;
319 OSStatus status
= SecKeyEncrypt(SECKEYREF(pubKey
), padding
,
320 plainText
, plainTextLen
, cipherText
, &ctlen
);
323 sslErrorLog("sslRsaEncrypt: SecKeyEncrypt failed (error %d)\n", status
);
326 /* Since the KeyExchange already allocated modulus size bytes we'll
327 use all of them. SecureTransport has always sent that many bytes,
328 so we're not going to deviate, to avoid interoperability issues. */
329 if (!status
&& (ctlen
< cipherTextLen
)) {
330 size_t offset
= cipherTextLen
- ctlen
;
331 memmove(cipherText
+ offset
, cipherText
, ctlen
);
332 memset(cipherText
, 0, offset
);
333 ctlen
= cipherTextLen
;
337 *actualBytes
= ctlen
;
340 sslErrorLog("***sslRsaEncrypt: error %d\n", status
);
346 OSStatus
sslRsaDecrypt(
349 const uint32_t padding
,
350 const uint8_t *cipherText
,
351 size_t cipherTextLen
,
352 uint8_t *plainText
, // mallocd by caller; RETURNED
353 size_t plainTextLen
, // available
354 size_t *actualBytes
) // RETURNED
357 gi_uint16 giPlainTextLen
= plainTextLen
;
360 assert(actualBytes
!= NULL
);
362 rsaStatus
= RSA_Decrypt(&privKey
->rsaKey
,
368 *actualBytes
= giPlainTextLen
;
370 return rsaStatus
? rsaStatusToSSL(rsaStatus
) : noErr
;
372 size_t ptlen
= plainTextLen
;
374 assert(actualBytes
!= NULL
);
376 OSStatus status
= SecKeyDecrypt(SECKEYREF(privKey
), padding
,
377 cipherText
, cipherTextLen
, plainText
, &ptlen
);
378 *actualBytes
= ptlen
;
381 sslErrorLog("sslRsaDecrypt: SecKeyDecrypt failed (error %d)\n", status
);
389 * Obtain size of the modulus of privKey in bytes.
391 size_t sslPrivKeyLengthInBytes(SSLPrivKey
*privKey
)
394 /* Get the length of p + q (which is the size of the modulus) in bits. */
395 gi_uint16 bitLen
= bitlen(&privKey
->rsaKey
.p
.g
) +
396 bitlen(&privKey
->rsaKey
.q
.g
);
397 /* Convert it to bytes. */
398 return (bitLen
+ 7) / 8;
400 return SecKeyGetBlockSize(SECKEYREF(privKey
));
405 * Obtain size of the modulus of pubKey in bytes.
407 size_t sslPubKeyLengthInBytes(SSLPubKey
*pubKey
)
410 /* Get the length of the modulus in bytes. */
411 return giantNumBytes(&pubKey
->rsaKey
.n
.g
);
413 return SecKeyGetBlockSize(SECKEYREF(pubKey
));
419 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
420 * ask the CSP to do this but that would be kind of expensive.
422 OSStatus
sslGetMaxSigSize(
426 assert(maxSigSize
!= NULL
);
429 #if RSA_SIG_SHARE_GIANT
430 *maxSigSize
= sizeof(RSASignBuffer
);
432 *maxSigSize
= MAX_PRIME_SIZE_BYTES
;
435 *maxSigSize
= SecKeyGetBlockSize(SECKEYREF(privKey
));
442 static OSStatus
sslGiantToBuffer(
443 SSLContext
*ctx
, // Currently unused.
453 ioLen
= serializeGiantBytes(g
);
454 status
= SSLAllocBuffer(buffer
, ioLen
, ctx
);
457 chars
= buffer
->data
;
459 /* Serialize the giant g into chars. */
460 giReturn
= serializeGiant(g
, chars
, &ioLen
);
462 SSLFreeBuffer(buffer
, ctx
);
463 return giReturnToSSL(giReturn
);
466 /* Trim off leading zeroes (but leave one zero if that's all there is). */
467 for (zeroCount
= 0; zeroCount
< (ioLen
- 1); ++zeroCount
)
468 if (chars
[zeroCount
])
472 buffer
->length
= ioLen
- zeroCount
;
473 memmove(chars
, chars
+ zeroCount
, buffer
->length
);
480 * Get raw key bits from an RSA public key.
482 OSStatus
sslGetPubKeyBits(
483 SSLContext
*ctx
, // Currently unused.
485 SSLBuffer
*modulus
, // data mallocd and RETURNED
486 SSLBuffer
*exponent
) // data mallocd and RETURNED
490 status
= sslGiantToBuffer(ctx
, &pubKey
->rsaKey
.n
.g
, modulus
);
494 status
= sslGiantToBuffer(ctx
, &pubKey
->rsaKey
.e
.g
, exponent
);
496 SSLFreeBuffer(modulus
, ctx
);
505 * Given raw RSA key bits, cook up a SSLPubKey. Used in
506 * Server-initiated key exchange.
508 OSStatus
sslGetPubKeyFromBits(
510 const SSLBuffer
*modulus
,
511 const SSLBuffer
*exponent
,
512 SSLPubKey
**pubKey
) // mallocd and RETURNED
520 modulus
->data
, modulus
->length
,
522 exponent
->data
, exponent
->length
525 key
= sslMalloc(sizeof(*key
));
526 rsaStatus
= rsaInitPubGKey(&apiKey
, &key
->rsaKey
);
529 return rsaStatusToSSL(rsaStatus
);
536 SecRSAPublicKeyParams params
= {
537 modulus
->data
, modulus
->length
,
538 exponent
->data
, exponent
->length
541 sslDebugLog("Creating RSA pub key from modulus=%p len=%lu exponent=%p len=%lu\n",
542 (uintptr_t)modulus
->data
, modulus
->length
,
543 (uintptr_t)exponent
->data
, exponent
->length
);
545 SecKeyRef key
= SecKeyCreateRSAPublicKey(NULL
, (const uint8_t *)¶ms
,
546 sizeof(params
), kSecKeyEncodingRSAPublicParams
);
548 sslErrorLog("sslGetPubKeyFromBits: SecKeyCreateRSAPublicKey failed\n");
552 size_t blocksize
= SecKeyGetBlockSize(key
);
553 sslDebugLog("sslGetPubKeyFromBits: RSA pub key block size=%lu\n", blocksize
);
555 *pubKey
= (SSLPubKey
*)key
;
561 #pragma mark Public Certificate Functions
563 #ifdef USE_SSLCERTIFICATE
566 * Given a SSLCertificate cert, obtain its public key as a SSLPubKey.
567 * Caller must sslFreePubKey and free the SSLPubKey itself.
569 OSStatus
sslPubKeyFromCert(
571 const SSLCertificate
*cert
,
572 SSLPubKey
**pubKey
) // RETURNED
575 DERSignedCertCrl signedCert
;
577 DERSubjPubKeyInfo pubKeyInfo
;
585 assert(pubKey
!= NULL
);
587 der
.data
= cert
->derCert
.data
;
588 der
.length
= cert
->derCert
.length
;
590 /* top level decode */
591 drtn
= DERParseSequence(&der
, DERNumSignedCertCrlItemSpecs
,
592 DERSignedCertCrlItemSpecs
, &signedCert
, sizeof(signedCert
));
594 return errSSLBadCert
;
596 /* decode the TBSCert - it was saved in full DER form */
597 drtn
= DERParseSequence(&signedCert
.tbs
,
598 DERNumTBSCertItemSpecs
, DERTBSCertItemSpecs
,
599 &tbsCert
, sizeof(tbsCert
));
601 return errSSLBadCert
;
603 /* sequence we're given: encoded DERSubjPubKeyInfo */
604 drtn
= DERParseSequenceContent(&tbsCert
.subjectPubKey
,
605 DERNumSubjPubKeyInfoItemSpecs
, DERSubjPubKeyInfoItemSpecs
,
606 &pubKeyInfo
, sizeof(pubKeyInfo
));
608 return errSSLBadCert
;
610 /* @@@ verify that this is an RSA key by decoding the AlgId */
613 * The contents of pubKeyInfo.pubKey is a bit string whose contents
614 * are a PKCS1 format RSA key.
616 drtn
= DERParseBitString(&pubKeyInfo
.pubKey
, &pubKeyPkcs1
, &numUnused
);
618 return errSSLBadCert
;
621 /* Now we have the public key in pkcs1 format. Let's make a public key
623 key
= sslMalloc(sizeof(*key
));
624 rsaStatus
= RSA_DecodePubKey(pubKeyPkcs1
.data
, pubKeyPkcs1
.length
,
630 SecKeyRef rsaPubKeyRef
= SecKeyCreateRSAPublicKey(NULL
,
631 pubKeyPkcs1
.data
, pubKeyPkcs1
.length
,
632 kSecKeyEncodingRSAPublicParams
);
633 rsaStatus
= (rsaPubKeyRef
) ? 0 : 1;
634 key
= (SSLPubKey
*)rsaPubKeyRef
;
637 return rsaStatusToSSL(rsaStatus
);
645 * Verify a chain of DER-encoded certs.
646 * First cert in a chain is root; this must also be present
647 * in ctx->trustedCerts.
649 * If arePeerCerts is true, host name verification is enabled and we
650 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
651 * we're just validating our own certs; no host name checking and
652 * peerSecTrust is transient.
654 OSStatus
sslVerifyCertChain(
656 const SSLCertificate
*certChain
,
659 OSStatus ortn
= noErr
;
663 /* No point checking our own certs, our clients can do that. */
667 CertVerifyReturn cvrtn
;
668 /* @@@ Add real cert checking. */
669 if (certChain
->next
) {
670 DERItem subject
, issuer
;
672 issuer
.data
= certChain
->derCert
.data
;
673 issuer
.length
= certChain
->derCert
.length
;
674 subject
.data
= certChain
->next
->derCert
.data
;
675 subject
.length
= certChain
->next
->derCert
.length
;
676 cvrtn
= certVerify(&subject
, &issuer
);
677 if (cvrtn
!= CVR_Success
)
678 ortn
= errSSLBadCert
;
682 sslErrorLog("***sslVerifyCertChain: only one cert in chain\n");
687 #else /* !USE_SSLCERTIFICATE */
692 CFArrayRef certChain
,
694 SecTrustRef
*pTrust
) /* RETURNED */
696 OSStatus status
= memFullErr
;
697 CFStringRef peerDomainName
= NULL
;
698 CFTypeRef policies
= NULL
;
699 SecTrustRef trust
= NULL
;
701 if (CFArrayGetCount(certChain
) == 0) {
702 status
= errSSLBadCert
;
707 if (ctx
->peerDomainNameLen
&& ctx
->peerDomainName
) {
708 CFIndex len
= ctx
->peerDomainNameLen
;
709 if (ctx
->peerDomainName
[len
- 1] == 0) {
711 //secwarning("peerDomainName is zero terminated!");
713 /* @@@ Double check that this is the correct encoding. */
714 require(peerDomainName
= CFStringCreateWithBytes(kCFAllocatorDefault
,
715 (const UInt8
*)ctx
->peerDomainName
, len
,
716 kCFStringEncodingUTF8
, false), errOut
);
719 /* If we are the client, our peer certificates must satisfy the
720 ssl server policy. */
721 bool server
= ctx
->protocolSide
== kSSLClientSide
;
722 require(policies
= SecPolicyCreateSSL(server
, peerDomainName
), errOut
);
724 require_noerr(status
= SecTrustCreateWithCertificates(certChain
, policies
,
727 /* If we have trustedAnchors we set them here. */
728 if (ctx
->trustedCerts
) {
729 require_noerr(status
= SecTrustSetAnchorCertificates(trust
,
730 ctx
->trustedCerts
), errOut
);
731 require_noerr(status
= SecTrustSetAnchorCertificatesOnly(trust
,
732 ctx
->trustedCertsOnly
), errOut
);
738 CFReleaseSafe(peerDomainName
);
739 CFReleaseSafe(policies
);
746 /* Return the first certificate reference from the supplied array
747 * whose data matches the given certificate, or NULL if none match.
750 sslGetMatchingCertInArray(
751 SecCertificateRef certRef
,
752 CFArrayRef certArray
)
754 SecCertificateRef matchedCert
= NULL
;
756 if (certRef
== NULL
|| certArray
== NULL
) {
760 CFDataRef certData
= SecCertificateCopyData(certRef
);
762 CFIndex idx
, count
= CFArrayGetCount(certArray
);
763 for(idx
=0; idx
<count
; idx
++) {
764 SecCertificateRef aCert
= (SecCertificateRef
)CFArrayGetValueAtIndex(certArray
, idx
);
765 CFDataRef aData
= SecCertificateCopyData(aCert
);
766 if (aData
&& CFEqual(aData
, certData
)) {
769 CFReleaseSafe(aData
);
773 CFReleaseSafe(certData
);
780 * Verify a chain of DER-encoded certs.
781 * Last cert in a chain is the leaf; this must also be present
782 * in ctx->trustedCerts.
784 * If arePeerCerts is true, host name verification is enabled and we
785 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
786 * we're just validating our own certs; no host name checking and
787 * peerSecTrust is transient.
789 extern OSStatus
sslVerifyCertChain(
791 CFArrayRef certChain
,
795 SecTrustRef trust
= NULL
;
800 /* renegotiate - start with a new SecTrustRef */
801 CFReleaseNull(ctx
->peerSecTrust
);
804 status
= sslCreateSecTrust(ctx
, certChain
, arePeerCerts
, &trust
);
806 if (!ctx
->enableCertVerify
) {
807 /* trivial case, this is caller's responsibility */
812 SecTrustResultType secTrustResult
;
813 require_noerr(status
= SecTrustEvaluate(trust
, &secTrustResult
), errOut
);
814 switch (secTrustResult
) {
815 case kSecTrustResultUnspecified
:
816 /* cert chain valid, no special UserTrust assignments */
817 case kSecTrustResultProceed
:
818 /* cert chain valid AND user explicitly trusts this */
821 case kSecTrustResultDeny
:
822 case kSecTrustResultConfirm
:
823 case kSecTrustResultRecoverableTrustFailure
:
825 if(ctx
->allowAnyRoot
) {
826 sslErrorLog("***Warning: accepting unverified cert chain\n");
831 * If the caller provided a list of trusted leaf certs, check them here
833 if(ctx
->trustedLeafCerts
) {
834 if (sslGetMatchingCertInArray((SecCertificateRef
)CFArrayGetValueAtIndex(certChain
, 0),
835 ctx
->trustedLeafCerts
)) {
840 status
= errSSLXCertChainInvalid
;
842 /* Do we really need to return things like:
844 errSSLUnknownRootCert
846 errSSLCertNotYetValid
847 errSSLHostNameMismatch
848 for our client to see what went wrong, or should we just always
850 errSSLXCertChainInvalid
851 when something is wrong? */
857 ctx
->peerSecTrust
= trust
;
859 CFReleaseSafe(trust
);
865 * Given a SecCertificateRef cert, obtain its public key as a SSLPubKey.
866 * Caller must sslFreePubKey and free the SSLPubKey itself.
868 extern OSStatus
sslCopyPeerPubKey(
872 OSStatus status
= noErr
;
875 check(ctx
->peerSecTrust
);
877 if (!ctx
->enableCertVerify
) {
878 SecTrustResultType result
;
879 require_noerr(status
= SecTrustEvaluate(ctx
->peerSecTrust
, &result
),
883 SecKeyRef key
= SecTrustCopyPublicKey(ctx
->peerSecTrust
);
885 sslErrorLog("sslCopyPeerPubKey: %s, ctx->peerSecTrust=%p\n",
886 "SecTrustCopyPublicKey failed", (uintptr_t)ctx
->peerSecTrust
);
887 return errSSLBadCert
;
889 *pubKey
= (SSLPubKey
*)key
;
893 sslErrorLog("sslCopyPeerPubKey: error %d\n", status
);
898 #endif /* !USE_SSLCERTIFICATE */
901 void stPrintCdsaError(const char *op
, OSStatus crtn
)
908 * After ciphersuite negotiation is complete, verify that we have
909 * the capability of actually performing the selected cipher.
910 * Currently we just verify that we have a cert and private signing
911 * key, if needed, and that the signing key's algorithm matches the
912 * expected key exchange method.
914 * This is currently called from FindCipherSpec(), after it sets
915 * ctx->selectedCipherSpec to a (supposedly) valid value, and from
916 * sslBuildCipherSpecArray(), in server mode (pre-negotiation) only.
918 OSStatus
sslVerifySelectedCipher(
920 const SSLCipherSpec
*selectedCipherSpec
)
922 if(ctx
->protocolSide
== kSSLClientSide
) {
925 #if SSL_PAC_SERVER_ENABLE
926 if((ctx
->masterSecretCallback
!= NULL
) &&
927 (ctx
->sessionTicket
.data
!= NULL
)) {
928 /* EAP via PAC resumption; we can do it */
931 #endif /* SSL_PAC_SERVER_ENABLE */
934 if(selectedCipherSpec
== NULL
) {
935 sslErrorLog("sslVerifySelectedCipher: no selected cipher\n");
936 return errSSLInternal
;
938 switch (selectedCipherSpec
->keyExchangeMethod
) {
942 case SSL_DH_RSA_EXPORT
:
944 case SSL_DHE_RSA_EXPORT
:
945 requireAlg
= kSecRSAAlgorithmID
;
948 case SSL_DHE_DSS_EXPORT
:
950 case SSL_DH_DSS_EXPORT
:
951 requireAlg
= kSecDSAAlgorithmID
;
954 case SSL_DH_anon_EXPORT
:
955 requireAlg
= kSecNullAlgorithmID
; /* no signing key */
958 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
959 * we'll need to add some logic here...
962 case SSL_ECDHE_ECDSA
:
967 requireAlg
= kSecECDSAAlgorithmID
;
972 /* needs update per cipherSpecs.c */
974 sslErrorLog("sslVerifySelectedCipher: unknown key exchange method\n");
975 return errSSLInternal
;
978 if(requireAlg
== kSecNullAlgorithmID
) {
982 /* private signing key required */
983 if(ctx
->signingPrivKeyRef
== NULL
) {
984 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
985 return errSSLBadConfiguration
;
988 /* Check the alg of our signing key. */
989 CFIndex keyAlg
= sslPrivKeyGetAlgorithmID(ctx
->signingPrivKeyRef
);
990 if (requireAlg
!= keyAlg
) {
991 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
992 return errSSLBadConfiguration
;
1000 /* FIXME: This is duplicated in SecDH */
1007 static const DERItemSpec DER_DHParamsItemSpecs
[] =
1009 { DER_OFFSET(DER_DHParams
, p
),
1011 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
1012 { DER_OFFSET(DER_DHParams
, g
),
1014 DER_DEC_NO_OPTS
| DER_ENC_SIGNED_INT
},
1015 { DER_OFFSET(DER_DHParams
, l
),
1017 DER_DEC_OPTIONAL
| DER_ENC_SIGNED_INT
},
1019 static const DERSize DER_NumDHParamsItemSpecs
=
1020 sizeof(DER_DHParamsItemSpecs
) / sizeof(DERItemSpec
);
1022 /* Max encoded size for standard (PKCS3) parameters */
1023 #define DH_ENCODED_PARAM_SIZE(primeSizeInBytes) \
1024 DER_MAX_ENCODED_SIZE( \
1025 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* g */ \
1026 DER_MAX_ENCODED_SIZE(primeSizeInBytes) + /* p */ \
1027 DER_MAX_ENCODED_SIZE(4)) /* l */
1030 OSStatus
sslDecodeDhParams(
1031 const SSLBuffer
*blob
, /* Input - PKCS-3 encoded */
1032 SSLBuffer
*prime
, /* Output - wire format */
1033 SSLBuffer
*generator
) /* Output - wire format */
1035 OSStatus ortn
= noErr
;
1037 DERItem paramItem
= {(DERByte
*)blob
->data
, blob
->length
};
1038 DER_DHParams decodedParams
;
1040 drtn
= DERParseSequence(¶mItem
,
1041 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
,
1042 &decodedParams
, sizeof(decodedParams
));
1046 prime
->data
= decodedParams
.p
.data
;
1047 prime
->length
= decodedParams
.p
.length
;
1049 generator
->data
= decodedParams
.g
.data
;
1050 generator
->length
= decodedParams
.g
.length
;
1056 OSStatus
sslEncodeDhParams(SSLBuffer
*blob
, /* data mallocd and RETURNED PKCS-3 encoded */
1057 const SSLBuffer
*prime
, /* Wire format */
1058 const SSLBuffer
*generator
) /* Wire format */
1060 OSStatus ortn
= noErr
;
1061 DER_DHParams derParams
=
1064 .length
= prime
->length
,
1065 .data
= prime
->data
,
1068 .length
= generator
->length
,
1069 .data
= generator
->data
,
1077 DERSize ioLen
= DH_ENCODED_PARAM_SIZE(derParams
.p
.length
);
1078 DERByte
*der
= sslMalloc(ioLen
);
1079 // FIXME: What if this fails - we should probably not have a malloc here ?
1081 ortn
= (OSStatus
)DEREncodeSequence(ASN1_CONSTR_SEQUENCE
,
1083 DER_NumDHParamsItemSpecs
, DER_DHParamsItemSpecs
,
1086 // This should never fail
1094 OSStatus
sslDhCreateKey(SSLContext
*ctx
)
1096 if (ctx
->secDHContext
) {
1097 SecDHDestroy(ctx
->secDHContext
);
1098 ctx
->secDHContext
= NULL
;
1101 /* Server params are set using encoded dh params */
1102 if (!(ctx
->dhParamsEncoded
.length
&& ctx
->dhParamsEncoded
.data
))
1103 return errSSLInternal
;
1105 if (SecDHCreateFromParameters(ctx
->dhParamsEncoded
.data
,
1106 ctx
->dhParamsEncoded
.length
, &ctx
->secDHContext
))
1107 return errSSLCrypto
;
1112 OSStatus
sslDhGenerateKeyPair(SSLContext
*ctx
)
1114 OSStatus ortn
= noErr
;
1116 require_noerr(ortn
= SSLAllocBuffer(&ctx
->dhExchangePublic
,
1117 SecDHGetMaxKeyLength(ctx
->secDHContext
), ctx
), out
);
1118 require_noerr(ortn
= SecDHGenerateKeypair(ctx
->secDHContext
,
1119 ctx
->dhExchangePublic
.data
, &ctx
->dhExchangePublic
.length
), out
);
1126 OSStatus
sslDhKeyExchange(SSLContext
*ctx
)
1128 OSStatus ortn
= noErr
;
1131 ctx
->secDHContext
== NULL
||
1132 ctx
->dhPeerPublic
.length
== 0) {
1133 /* comes from peer, don't panic */
1134 sslErrorLog("sslDhKeyExchange: null peer public key\n");
1135 return errSSLProtocol
;
1138 require_noerr(ortn
= SSLAllocBuffer(&ctx
->preMasterSecret
,
1139 SecDHGetMaxKeyLength(ctx
->secDHContext
), ctx
), out
);
1140 require_noerr(ortn
= SecDHComputeKey(ctx
->secDHContext
,
1141 ctx
->dhPeerPublic
.data
, ctx
->dhPeerPublic
.length
,
1142 ctx
->preMasterSecret
.data
, &ctx
->preMasterSecret
.length
), out
);
1146 sslErrorLog("sslDhKeyExchange: failed to compute key (error %d)\n", ortn
);
1150 #endif /* APPLE_DH */
1153 * Given an ECDSA key in SecKey format, extract the SSL_ECDSA_NamedCurve
1154 * from its algorithm parameters.
1156 OSStatus
sslEcdsaPeerCurve(
1158 SSL_ECDSA_NamedCurve
*namedCurve
)
1160 /* Cast is safe because enums are kept in sync. */
1161 *namedCurve
= (SSL_ECDSA_NamedCurve
)SecECKeyGetNamedCurve(SECKEYREF(pubKey
));
1162 if (*namedCurve
== kSecECCurveNone
) {
1163 sslErrorLog("sslEcdsaPeerCurve: no named curve for public key\n");
1164 return errSSLProtocol
;
1170 * Generate ECDH key pair with the given SSL_ECDSA_NamedCurve.
1171 * Private key, in ref form, is placed in ctx->ecdhPrivate.
1172 * Public key, in ECPoint form - which can NOT be used as
1173 * a key in any CSP ops - is placed in ecdhExchangePublic.
1175 OSStatus
sslEcdhGenerateKeyPair(
1177 SSL_ECDSA_NamedCurve namedCurve
)
1179 OSStatus ortn
= noErr
;
1182 switch (namedCurve
) {
1183 case SSL_Curve_secp256r1
:
1186 case SSL_Curve_secp384r1
:
1189 case SSL_Curve_secp521r1
:
1193 /* should not have gotten this far */
1194 sslErrorLog("sslEcdhGenerateKeyPair: bad namedCurve (%u)\n",
1195 (unsigned)namedCurve
);
1196 return errSSLInternal
;
1199 ccec_generate_key(cp
, CCRNGSTATE
, ctx
->ecdhContext
);
1200 size_t pub_size
= ccec_export_pub_size(ctx
->ecdhContext
);
1201 SSLFreeBuffer(&ctx
->ecdhExchangePublic
, ctx
);
1202 require_noerr(ortn
= SSLAllocBuffer(&ctx
->ecdhExchangePublic
,
1203 pub_size
, ctx
), errOut
);
1204 ccec_export_pub(ctx
->ecdhContext
, ctx
->ecdhExchangePublic
.data
);
1206 sslDebugLog("sslEcdhGenerateKeyPair: pub key size=%ld, data=%p\n",
1207 pub_size
, (uintptr_t)ctx
->ecdhExchangePublic
.data
);
1214 * Perform ECDH key exchange. Obtained key material is the same
1215 * size as our private key.
1217 * On entry, ecdhPrivate is our private key. The peer's public key
1218 * is either ctx->ecdhPeerPublic for ECDHE exchange, or
1219 * ctx->peerPubKey for ECDH exchange.
1221 OSStatus
sslEcdhKeyExchange(
1223 SSLBuffer
*exchanged
)
1225 OSStatus ortn
= noErr
;
1226 CFDataRef pubKeyData
= NULL
;
1227 const unsigned char *pubKeyBits
;
1228 unsigned long pubKeyLen
;
1230 switch(ctx
->selectedCipherSpec
.keyExchangeMethod
) {
1231 case SSL_ECDHE_ECDSA
:
1233 /* public key passed in as CSSM_DATA *Param */
1234 if(ctx
->ecdhPeerPublic
.length
== 0) {
1235 /* comes from peer, don't panic */
1236 sslErrorLog("sslEcdhKeyExchange: null peer public key\n");
1237 ortn
= errSSLProtocol
;
1240 pubKeyBits
= ctx
->ecdhPeerPublic
.data
;
1241 pubKeyLen
= ctx
->ecdhPeerPublic
.length
;
1243 case SSL_ECDH_ECDSA
:
1245 /* Use the public key provided by the peer. */
1246 if(ctx
->peerPubKey
== NULL
) {
1247 sslErrorLog("sslEcdhKeyExchange: no peer key\n");
1248 ortn
= errSSLInternal
;
1252 pubKeyData
= SecECKeyCopyPublicBits(SECKEYREF(ctx
->peerPubKey
));
1254 sslErrorLog("sslEcdhKeyExchange: SecECKeyCopyPublicBits failed\n");
1255 ortn
= errSSLProtocol
;
1258 pubKeyBits
= CFDataGetBytePtr(pubKeyData
);
1259 pubKeyLen
= CFDataGetLength(pubKeyData
);
1262 /* shouldn't be here */
1263 sslErrorLog("sslEcdhKeyExchange: unknown keyExchangeMethod (%d)\n",
1264 ctx
->selectedCipherSpec
.keyExchangeMethod
);
1266 ortn
= errSSLInternal
;
1270 ccec_const_cp_t cp
= ccec_ctx_cp(ctx
->ecdhContext
);
1271 ccec_pub_ctx_decl(ccn_sizeof(521), pubKey
);
1272 ccec_import_pub(cp
, pubKeyLen
, pubKeyBits
, pubKey
);
1273 size_t len
= 1 + 2 * ccec_ccn_size(cp
);
1274 require_noerr(ortn
= SSLAllocBuffer(exchanged
, len
, NULL
), errOut
);
1275 require_noerr(ccec_compute_key(ctx
->ecdhContext
, pubKey
, &exchanged
->length
, exchanged
->data
), errOut
);
1277 sslDebugLog("sslEcdhKeyExchange: exchanged key length=%ld, data=%p\n",
1278 exchanged
->length
, (uintptr_t)exchanged
->data
);
1281 CFReleaseSafe(pubKeyData
);