2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 File: sslKeyExchange.c
22 Contains: Support for key exchange and server key exchange
24 Written by: Doug Mitchell
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
30 #include "sslContext.h"
31 #include "sslHandshake.h"
32 #include "sslMemory.h"
35 #include "appleCdsa.h"
36 #include "sslDigests.h"
37 #include "ModuleAttacher.h"
43 #include <Security/globalizer.h>
44 #include <Security/threading.h>
47 #pragma mark *** forward static declarations ***
48 static OSStatus
SSLGenServerDHParamsAndKey(SSLContext
*ctx
);
49 static OSStatus
SSLEncodeDHKeyParams(SSLContext
*ctx
, UInt8
*charPtr
);
50 static OSStatus
SSLDecodeDHKeyParams(SSLContext
*ctx
, UInt8
*&charPtr
,
53 #define DH_PARAM_DUMP 0
56 static void dumpBuf(const char *name
, SSLBuffer
&buf
)
58 printf("%s:\n", name
);
60 UInt8
*endCp
= cp
+ buf
.length
;
63 for(unsigned i
=0; i
<16; i
++) {
64 printf("%02x ", *cp
++);
78 #endif /* DH_PARAM_DUMP */
83 #pragma mark *** local D-H parameter generator ***
85 * Process-wide server-supplied Diffie-Hellman parameters.
86 * This might be overridden by some API_supplied parameters
94 const SSLBuffer
&prime() { return mPrime
; }
95 const SSLBuffer
&generator() { return mGenerator
; }
96 const SSLBuffer
¶mBlock() { return mParamBlock
; }
99 /* these two for sending over the wire */
101 SSLBuffer mGenerator
;
102 /* this one for sending to the CSP at key gen time */
103 SSLBuffer mParamBlock
;
106 ServerDhParams::ServerDhParams()
110 mGenerator
.data
= NULL
;
111 mGenerator
.length
= 0;
112 mParamBlock
.data
= NULL
;
113 mParamBlock
.length
= 0;
115 CSSM_CSP_HANDLE cspHand
;
116 CSSM_CL_HANDLE clHand
; // not used here, just for
118 CSSM_TP_HANDLE tpHand
; // ditto
121 crtn
= attachToModules(&cspHand
, &clHand
, &tpHand
);
123 MacOSError::throwMe(errSSLModuleAttach
);
126 CSSM_CC_HANDLE ccHandle
;
127 CSSM_DATA cParams
= {0, NULL
};
129 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
131 SSL_DH_DEFAULT_PRIME_SIZE
,
136 &cParams
, // Params, may be NULL
139 stPrintCdsaError("ServerDhParams CSSM_CSP_CreateKeyGenContext", crtn
);
140 MacOSError::throwMe(errSSLCrypto
);
143 /* explicitly generate params and save them */
144 sslDhDebug("^^^generating Diffie-Hellman parameters...");
145 crtn
= CSSM_GenerateAlgorithmParams(ccHandle
,
146 SSL_DH_DEFAULT_PRIME_SIZE
, &cParams
);
148 stPrintCdsaError("ServerDhParams CSSM_GenerateAlgorithmParams", crtn
);
149 CSSM_DeleteContext(ccHandle
);
150 MacOSError::throwMe(errSSLCrypto
);
152 CSSM_TO_SSLBUF(&cParams
, &mParamBlock
);
153 OSStatus ortn
= sslDecodeDhParams(&mParamBlock
, &mPrime
, &mGenerator
);
155 sslErrorLog("ServerDhParams: param decode error\n");
156 MacOSError::throwMe(ortn
);
158 CSSM_DeleteContext(ccHandle
);
161 ServerDhParams::~ServerDhParams()
163 sslFree(mPrime
.data
);
164 sslFree(mGenerator
.data
);
165 sslFree(mParamBlock
.data
);
168 /* the single global thing */
169 static ModuleNexus
<ServerDhParams
> serverDhParams
;
171 #endif /* APPLE_DH */
174 #pragma mark *** RSA key exchange ***
177 * Client RSA Key Exchange msgs actually start with a two-byte
178 * length field, contrary to the first version of RFC 2246, dated
179 * January 1999. See RFC 2246, March 2002, section 7.4.7.1 for
180 * updated requirements.
182 #define RSA_CLIENT_KEY_ADD_LENGTH 1
184 typedef CSSM_KEY_PTR SSLRSAPrivateKey
;
187 SSLEncodeRSAKeyParams(SSLBuffer
*keyParams
, SSLRSAPrivateKey
*key
, SSLContext
*ctx
)
189 SSLBuffer modulus
, exponent
;
192 if(err
= attachToCsp(ctx
)) {
196 /* Note currently ALL public keys are raw, obtained from the CL... */
197 assert((*key
)->KeyHeader
.BlobType
== CSSM_KEYBLOB_RAW
);
198 err
= sslGetPubKeyBits(ctx
,
204 SSLFreeBuffer(modulus
, ctx
);
205 SSLFreeBuffer(exponent
, ctx
);
209 if ((err
= SSLAllocBuffer(*keyParams
,
210 modulus
.length
+ exponent
.length
+ 4, ctx
)) != 0) {
213 charPtr
= keyParams
->data
;
214 charPtr
= SSLEncodeInt(charPtr
, modulus
.length
, 2);
215 memcpy(charPtr
, modulus
.data
, modulus
.length
);
216 charPtr
+= modulus
.length
;
217 charPtr
= SSLEncodeInt(charPtr
, exponent
.length
, 2);
218 memcpy(charPtr
, exponent
.data
, exponent
.length
);
220 /* these were mallocd by sslGetPubKeyBits() */
221 SSLFreeBuffer(modulus
, ctx
);
222 SSLFreeBuffer(exponent
, ctx
);
227 SSLEncodeRSAPremasterSecret(SSLContext
*ctx
)
228 { SSLBuffer randData
;
230 SSLProtocolVersion maxVersion
;
232 if ((err
= SSLAllocBuffer(ctx
->preMasterSecret
,
233 SSL_RSA_PREMASTER_SECRET_SIZE
, ctx
)) != 0)
236 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
237 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
238 sslGetMaxProtVersion(ctx
, &maxVersion
);
239 SSLEncodeInt(ctx
->preMasterSecret
.data
, maxVersion
, 2);
240 randData
.data
= ctx
->preMasterSecret
.data
+2;
241 randData
.length
= SSL_RSA_PREMASTER_SECRET_SIZE
- 2;
242 if ((err
= sslRand(ctx
, &randData
)) != 0)
248 * Generate a server key exchange message signed by our RSA or DSA private key.
251 SSLEncodeSignedServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
255 UInt8 hashes
[SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
];
256 SSLBuffer exchangeParams
,clientRandom
,serverRandom
,hashCtx
, hash
;
258 UInt32 dataToSignLen
;
263 const CSSM_KEY
*cssmKey
;
265 assert(ctx
->protocolSide
== SSL_ServerSide
);
266 assert(ctx
->signingPubKey
!= NULL
);
267 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
268 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
269 exchangeParams
.data
= 0;
273 /* Set up parameter block to hash ==> exchangeParams */
274 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
278 * Parameter block = encryption public key.
279 * If app hasn't supplied a separate encryption cert, abort.
281 if(ctx
->encryptPubKey
== NULL
) {
282 sslErrorLog("RSAServerKeyExchange: no encrypt cert\n");
283 return errSSLBadConfiguration
;
285 err
= SSLEncodeRSAKeyParams(&exchangeParams
,
286 &ctx
->encryptPubKey
, ctx
);
291 case SSL_DHE_DSS_EXPORT
:
293 /* and fall through */
295 case SSL_DHE_RSA_EXPORT
:
298 * Parameter block = {prime, generator, public key}
299 * Obtain D-H parameters (if we don't have them) and a key pair.
301 err
= SSLGenServerDHParamsAndKey(ctx
);
305 UInt32 len
= ctx
->dhParamsPrime
.length
+
306 ctx
->dhParamsGenerator
.length
+
307 ctx
->dhExchangePublic
.length
+ 6 /* 3 length fields */;
308 err
= SSLAllocBuffer(exchangeParams
, len
, ctx
);
312 err
= SSLEncodeDHKeyParams(ctx
, exchangeParams
.data
);
315 #endif /* APPLE_DH */
317 /* shouldn't be here */
319 return errSSLInternal
;
325 /* cook up hash(es) for raw sign */
326 clientRandom
.data
= ctx
->clientRandom
;
327 clientRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
328 serverRandom
.data
= ctx
->serverRandom
;
329 serverRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
332 /* skip this if signing with DSA */
334 dataToSignLen
= SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
;
335 hash
.data
= &hashes
[0];
336 hash
.length
= SSL_MD5_DIGEST_LEN
;
338 if ((err
= ReadyHash(SSLHashMD5
, hashCtx
, ctx
)) != 0)
340 if ((err
= SSLHashMD5
.update(hashCtx
, clientRandom
)) != 0)
342 if ((err
= SSLHashMD5
.update(hashCtx
, serverRandom
)) != 0)
344 if ((err
= SSLHashMD5
.update(hashCtx
, exchangeParams
)) != 0)
346 if ((err
= SSLHashMD5
.final(hashCtx
, hash
)) != 0)
348 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
352 /* DSA - just use the SHA1 hash */
353 dataToSign
= &hashes
[SSL_MD5_DIGEST_LEN
];
354 dataToSignLen
= SSL_SHA1_DIGEST_LEN
;
356 hash
.data
= &hashes
[SSL_MD5_DIGEST_LEN
];
357 hash
.length
= SSL_SHA1_DIGEST_LEN
;
358 if ((err
= ReadyHash(SSLHashSHA1
, hashCtx
, ctx
)) != 0)
360 if ((err
= SSLHashSHA1
.update(hashCtx
, clientRandom
)) != 0)
362 if ((err
= SSLHashSHA1
.update(hashCtx
, serverRandom
)) != 0)
364 if ((err
= SSLHashSHA1
.update(hashCtx
, exchangeParams
)) != 0)
366 if ((err
= SSLHashSHA1
.final(hashCtx
, hash
)) != 0)
368 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
371 /* preallocate a buffer for signing */
372 err
= SecKeyGetCSSMKey(ctx
->signingPrivKeyRef
, &cssmKey
);
374 sslErrorLog("SSLEncodeSignedServerKeyExchange: SecKeyGetCSSMKey err %d\n",
378 err
= sslGetMaxSigSize(cssmKey
, maxSigLen
);
382 err
= SSLAllocBuffer(signature
, maxSigLen
, ctx
);
387 err
= sslRawSign(ctx
,
388 ctx
->signingPrivKeyRef
,
389 dataToSign
, // one or two hashes
397 assert(actSigLen
<= maxSigLen
);
399 /* package it all up */
400 outputLen
= exchangeParams
.length
+ 2 + actSigLen
;
401 keyExch
.protocolVersion
= ctx
->negProtocolVersion
;
402 keyExch
.contentType
= SSL_RecordTypeHandshake
;
403 if ((err
= SSLAllocBuffer(keyExch
.contents
, outputLen
+4, ctx
)) != 0)
406 charPtr
= keyExch
.contents
.data
;
407 *charPtr
++ = SSL_HdskServerKeyExchange
;
408 charPtr
= SSLEncodeInt(charPtr
, outputLen
, 3);
410 memcpy(charPtr
, exchangeParams
.data
, exchangeParams
.length
);
411 charPtr
+= exchangeParams
.length
;
412 charPtr
= SSLEncodeInt(charPtr
, actSigLen
, 2);
413 memcpy(charPtr
, signature
.data
, actSigLen
);
414 assert((charPtr
+ actSigLen
) ==
415 (keyExch
.contents
.data
+ keyExch
.contents
.length
));
420 SSLFreeBuffer(hashCtx
, ctx
);
421 SSLFreeBuffer(exchangeParams
, ctx
);
422 SSLFreeBuffer(signature
, ctx
);
427 * Decode and verify a server key exchange message signed by server's
431 SSLDecodeSignedServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
434 SSLBuffer hashOut
, hashCtx
, clientRandom
, serverRandom
;
435 UInt16 modulusLen
, exponentLen
, signatureLen
;
436 UInt8
*modulus
, *exponent
, *signature
;
437 UInt8 hashes
[SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
];
438 SSLBuffer signedHashes
;
440 UInt32 dataToSignLen
;
443 assert(ctx
->protocolSide
== SSL_ClientSide
);
444 signedHashes
.data
= 0;
447 if (message
.length
< 2) {
448 sslErrorLog("SSLDecodeSignedServerKeyExchange: msg len error 1\n");
449 return errSSLProtocol
;
452 /* first extract the key-exchange-method-specific parameters */
453 UInt8
*charPtr
= message
.data
;
454 UInt8
*endCp
= charPtr
+ message
.length
;
455 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
458 modulusLen
= SSLDecodeInt(charPtr
, 2);
460 if((charPtr
+ modulusLen
) > endCp
) {
461 sslErrorLog("signedServerKeyExchange: msg len error 2\n");
462 return errSSLProtocol
;
465 charPtr
+= modulusLen
;
467 exponentLen
= SSLDecodeInt(charPtr
, 2);
469 if((charPtr
+ exponentLen
) > endCp
) {
470 sslErrorLog("signedServerKeyExchange: msg len error 3\n");
471 return errSSLProtocol
;
474 charPtr
+= exponentLen
;
478 case SSL_DHE_DSS_EXPORT
:
480 /* and fall through */
482 case SSL_DHE_RSA_EXPORT
:
483 err
= SSLDecodeDHKeyParams(ctx
, charPtr
, message
.length
);
488 #endif /* APPLE_DH */
491 return errSSLInternal
;
494 /* this is what's hashed */
495 SSLBuffer signedParams
;
496 signedParams
.data
= message
.data
;
497 signedParams
.length
= charPtr
- message
.data
;
499 signatureLen
= SSLDecodeInt(charPtr
, 2);
501 if((charPtr
+ signatureLen
) != endCp
) {
502 sslErrorLog("signedServerKeyExchange: msg len error 4\n");
503 return errSSLProtocol
;
507 clientRandom
.data
= ctx
->clientRandom
;
508 clientRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
509 serverRandom
.data
= ctx
->serverRandom
;
510 serverRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
513 /* skip this if signing with DSA */
515 dataToSignLen
= SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
;
516 hashOut
.data
= hashes
;
517 hashOut
.length
= SSL_MD5_DIGEST_LEN
;
519 if ((err
= ReadyHash(SSLHashMD5
, hashCtx
, ctx
)) != 0)
521 if ((err
= SSLHashMD5
.update(hashCtx
, clientRandom
)) != 0)
523 if ((err
= SSLHashMD5
.update(hashCtx
, serverRandom
)) != 0)
525 if ((err
= SSLHashMD5
.update(hashCtx
, signedParams
)) != 0)
527 if ((err
= SSLHashMD5
.final(hashCtx
, hashOut
)) != 0)
531 /* DSA - just use the SHA1 hash */
532 dataToSign
= &hashes
[SSL_MD5_DIGEST_LEN
];
533 dataToSignLen
= SSL_SHA1_DIGEST_LEN
;
535 hashOut
.data
= hashes
+ SSL_MD5_DIGEST_LEN
;
536 hashOut
.length
= SSL_SHA1_DIGEST_LEN
;
537 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
540 if ((err
= ReadyHash(SSLHashSHA1
, hashCtx
, ctx
)) != 0)
542 if ((err
= SSLHashSHA1
.update(hashCtx
, clientRandom
)) != 0)
544 if ((err
= SSLHashSHA1
.update(hashCtx
, serverRandom
)) != 0)
546 if ((err
= SSLHashSHA1
.update(hashCtx
, signedParams
)) != 0)
548 if ((err
= SSLHashSHA1
.final(hashCtx
, hashOut
)) != 0)
551 err
= sslRawVerify(ctx
,
554 dataToSign
, /* plaintext */
555 dataToSignLen
, /* plaintext length */
559 sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
560 "returned %d\n", (int)err
);
564 /* Signature matches; now replace server key with new key */
565 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
572 /* first free existing peerKey */
573 sslFreeKey(ctx
->peerPubKeyCsp
,
575 NULL
); /* no KCItem */
577 /* and cook up a new one from raw bits */
578 modBuf
.data
= modulus
;
579 modBuf
.length
= modulusLen
;
580 expBuf
.data
= exponent
;
581 expBuf
.length
= exponentLen
;
582 err
= sslGetPubKeyFromBits(ctx
,
586 &ctx
->peerPubKeyCsp
);
590 case SSL_DHE_RSA_EXPORT
:
592 case SSL_DHE_DSS_EXPORT
:
593 break; /* handled above */
595 assert(0); /* handled above */
598 SSLFreeBuffer(signedHashes
, ctx
);
599 SSLFreeBuffer(hashCtx
, ctx
);
604 SSLDecodeRSAKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
606 UInt32 outputLen
, localKeyModulusLen
;
607 SSLProtocolVersion version
;
608 Boolean useEncryptKey
= false;
610 SecKeyRef keyRef
= NULL
;
611 const CSSM_KEY
*cssmKey
;
613 assert(ctx
->protocolSide
== SSL_ServerSide
);
615 #if SSL_SERVER_KEYEXCH_HACK
617 * the way we work with Netscape.
618 * FIXME - maybe we should *require* an encryptPrivKey in this
621 if((ctx
->selectedCipherSpec
->keyExchangeMethod
== SSL_RSA_EXPORT
) &&
622 (ctx
->encryptPrivKey
!= NULL
)) {
623 useEncryptKey
= true;
626 #else /* !SSL_SERVER_KEYEXCH_HACK */
627 /* The "correct" way, I think, which doesn't work with Netscape */
628 if (ctx
->encryptPrivKeyRef
) {
629 useEncryptKey
= true;
631 #endif /* SSL_SERVER_KEYEXCH_HACK */
633 keyRef
= ctx
->encryptPrivKeyRef
;
634 /* FIXME: when 3420180 is implemented, pick appropriate creds here */
637 keyRef
= ctx
->signingPrivKeyRef
;
638 /* FIXME: when 3420180 is implemented, pick appropriate creds here */
640 err
= SecKeyGetCSSMKey(keyRef
, &cssmKey
);
642 sslErrorLog("SSLDecodeRSAKeyExchange: SecKeyGetCSSMKey err %d\n",
647 localKeyModulusLen
= sslKeyLengthInBytes(cssmKey
);
650 * We have to tolerate incoming key exchange msgs with and without the
651 * two-byte "encrypted length" field.
653 if (keyExchange
.length
== localKeyModulusLen
) {
654 /* no length encoded */
655 src
= keyExchange
.data
;
657 else if((keyExchange
.length
== (localKeyModulusLen
+ 2)) &&
658 (ctx
->negProtocolVersion
>= TLS_Version_1_0
)) {
659 /* TLS only - skip the length bytes */
660 src
= keyExchange
.data
+ 2;
663 sslErrorLog("SSLDecodeRSAKeyExchange: length error (exp %u got %u)\n",
664 (unsigned)localKeyModulusLen
, (unsigned)keyExchange
.length
);
665 return errSSLProtocol
;
667 err
= SSLAllocBuffer(ctx
->preMasterSecret
, SSL_RSA_PREMASTER_SECRET_SIZE
, ctx
);
673 * From this point on, to defend against the Bleichenbacher attack
674 * and its Klima-Pokorny-Rosa variant, any errors we detect are *not*
675 * reported to the caller or the peer. If we detect any error during
676 * decryption (e.g., bad PKCS1 padding) or in the testing of the version
677 * number in the premaster secret, we proceed by generating a random
678 * premaster secret, with the correct version number, and tell our caller
679 * that everything is fine. This session will fail as soon as the
680 * finished messages are sent, since we will be using a bogus premaster
681 * secret (and hence bogus session and MAC keys). Meanwhile we have
682 * not provided any side channel information relating to the cause of
685 * See http://eprint.iacr.org/2003/052/ for more info.
687 err
= sslRsaDecrypt(ctx
,
690 localKeyModulusLen
, // ciphertext len
691 ctx
->preMasterSecret
.data
,
692 SSL_RSA_PREMASTER_SECRET_SIZE
, // plaintext buf available
696 /* possible Bleichenbacher attack */
697 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: RSA decrypt fail");
699 else if(outputLen
!= SSL_RSA_PREMASTER_SECRET_SIZE
) {
700 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: premaster secret size error");
701 err
= errSSLProtocol
; // not passed back to caller
706 * Two legal values here - the one we actually negotiated (which is
707 * technically incorrect but not uncommon), and the one the client
708 * sent as its preferred version in the client hello msg.
710 version
= (SSLProtocolVersion
)SSLDecodeInt(ctx
->preMasterSecret
.data
, 2);
711 if((version
!= ctx
->negProtocolVersion
) &&
712 (version
!= ctx
->clientReqProtocol
)) {
713 /* possible Klima-Pokorny-Rosa attack */
714 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: version error");
715 err
= errSSLProtocol
;
720 * Obfuscate failures for defense against Bleichenbacher and
721 * Klima-Pokorny-Rosa attacks.
723 SSLEncodeInt(ctx
->preMasterSecret
.data
, ctx
->negProtocolVersion
, 2);
725 tmpBuf
.data
= ctx
->preMasterSecret
.data
+ 2;
726 tmpBuf
.length
= SSL_RSA_PREMASTER_SECRET_SIZE
- 2;
727 /* must ignore failures here */
728 sslRand(ctx
, &tmpBuf
);
731 /* in any case, save premaster secret (good or bogus) and proceed */
736 SSLEncodeRSAKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
738 UInt32 outputLen
, peerKeyModulusLen
;
741 bool encodeLen
= false;
743 assert(ctx
->protocolSide
== SSL_ClientSide
);
744 if ((err
= SSLEncodeRSAPremasterSecret(ctx
)) != 0)
747 keyExchange
.contentType
= SSL_RecordTypeHandshake
;
748 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
749 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
750 keyExchange
.protocolVersion
= ctx
->negProtocolVersion
;
752 peerKeyModulusLen
= sslKeyLengthInBytes(ctx
->peerPubKey
);
753 bufLen
= peerKeyModulusLen
+ 4;
754 #if RSA_CLIENT_KEY_ADD_LENGTH
755 if(ctx
->negProtocolVersion
>= TLS_Version_1_0
) {
760 if ((err
= SSLAllocBuffer(keyExchange
.contents
,
765 dst
= keyExchange
.contents
.data
+ 4;
769 keyExchange
.contents
.data
[0] = SSL_HdskClientKeyExchange
;
771 /* this is the record payload length */
772 SSLEncodeInt(keyExchange
.contents
.data
+ 1, bufLen
- 4, 3);
774 /* the length of the encrypted pre_master_secret */
775 SSLEncodeInt(keyExchange
.contents
.data
+ 4,
776 peerKeyModulusLen
, 2);
778 err
= sslRsaEncrypt(ctx
,
780 /* FIXME - maybe this should be ctx->cspHand */
782 ctx
->preMasterSecret
.data
,
783 SSL_RSA_PREMASTER_SECRET_SIZE
,
791 assert(outputLen
== encodeLen
?
792 keyExchange
.contents
.length
- 6 :
793 keyExchange
.contents
.length
- 4 );
802 #pragma mark *** Diffie-Hellman key exchange ***
805 * Diffie-Hellman setup, server side. On successful return, the
806 * following SSLContext members are valid:
814 SSLGenServerDHParamsAndKey(
818 assert(ctx
->protocolSide
== SSL_ServerSide
);
821 * Obtain D-H parameters if we don't have them.
823 if(ctx
->dhParamsPrime
.data
== NULL
) {
824 assert(ctx
->dhParamsGenerator
.data
== NULL
);
825 const SSLBuffer
&pr
= serverDhParams().prime();
826 ortn
= SSLCopyBuffer(pr
, ctx
->dhParamsPrime
);
830 const SSLBuffer
&gen
= serverDhParams().generator();
831 ortn
= SSLCopyBuffer(gen
, ctx
->dhParamsGenerator
);
835 const SSLBuffer
&block
= serverDhParams().paramBlock();
836 ortn
= SSLCopyBuffer(block
, ctx
->dhParamsEncoded
);
842 /* generate per-session D-H key pair */
843 sslFreeKey(ctx
->cspHand
, &ctx
->dhPrivate
, NULL
);
844 SSLFreeBuffer(ctx
->dhExchangePublic
, ctx
);
845 ctx
->dhPrivate
= (CSSM_KEY
*)sslMalloc(sizeof(CSSM_KEY
));
847 ortn
= sslDhGenerateKeyPair(ctx
,
848 ctx
->dhParamsEncoded
,
849 ctx
->dhParamsPrime
.length
* 8,
850 &pubKey
, ctx
->dhPrivate
);
854 CSSM_TO_SSLBUF(&pubKey
.KeyData
, &ctx
->dhExchangePublic
);
859 * Encode DH params and public key in caller-supplied buffer.
862 SSLEncodeDHKeyParams(
866 assert(ctx
->protocolSide
== SSL_ServerSide
);
867 assert(ctx
->dhParamsPrime
.data
!= NULL
);
868 assert(ctx
->dhParamsGenerator
.data
!= NULL
);
869 assert(ctx
->dhExchangePublic
.data
!= NULL
);
871 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhParamsPrime
.length
, 2);
872 memcpy(charPtr
, ctx
->dhParamsPrime
.data
, ctx
->dhParamsPrime
.length
);
873 charPtr
+= ctx
->dhParamsPrime
.length
;
875 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhParamsGenerator
.length
, 2);
876 memcpy(charPtr
, ctx
->dhParamsGenerator
.data
,
877 ctx
->dhParamsGenerator
.length
);
878 charPtr
+= ctx
->dhParamsGenerator
.length
;
880 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhExchangePublic
.length
, 2);
881 memcpy(charPtr
, ctx
->dhExchangePublic
.data
,
882 ctx
->dhExchangePublic
.length
);
884 dumpBuf("server prime", ctx
->dhParamsPrime
);
885 dumpBuf("server generator", ctx
->dhParamsGenerator
);
886 dumpBuf("server pub key", ctx
->dhExchangePublic
);
891 * Decode DH params and server public key.
894 SSLDecodeDHKeyParams(
896 UInt8
*&charPtr
, // IN/OUT
899 OSStatus err
= noErr
;
901 assert(ctx
->protocolSide
== SSL_ClientSide
);
902 UInt8
*endCp
= charPtr
+ length
;
904 /* Allow reuse via renegotiation */
905 SSLFreeBuffer(ctx
->dhParamsPrime
, ctx
);
906 SSLFreeBuffer(ctx
->dhParamsGenerator
, ctx
);
907 SSLFreeBuffer(ctx
->dhPeerPublic
, ctx
);
909 /* Prime, with a two-byte length */
910 UInt32 len
= SSLDecodeInt(charPtr
, 2);
912 if((charPtr
+ len
) > endCp
) {
913 return errSSLProtocol
;
915 err
= SSLAllocBuffer(ctx
->dhParamsPrime
, len
, ctx
);
919 memmove(ctx
->dhParamsPrime
.data
, charPtr
, len
);
922 /* Generator, with a two-byte length */
923 len
= SSLDecodeInt(charPtr
, 2);
925 if((charPtr
+ len
) > endCp
) {
926 return errSSLProtocol
;
928 err
= SSLAllocBuffer(ctx
->dhParamsGenerator
, len
, ctx
);
932 memmove(ctx
->dhParamsGenerator
.data
, charPtr
, len
);
935 /* peer public key, with a two-byte length */
936 len
= SSLDecodeInt(charPtr
, 2);
938 err
= SSLAllocBuffer(ctx
->dhPeerPublic
, len
, ctx
);
942 memmove(ctx
->dhPeerPublic
.data
, charPtr
, len
);
945 dumpBuf("client peer pub", ctx
->dhPeerPublic
);
946 dumpBuf("client prime", ctx
->dhParamsPrime
);
947 dumpBuf("client generator", ctx
->dhParamsGenerator
);
953 * Given the server's Diffie-Hellman parameters, generate our
954 * own DH key pair, and perform key exchange using the server's
955 * public key and our private key. The result is the premaster
958 * SSLContext members valid on entry:
963 * SSLContext members valid on successful return:
969 SSLGenClientDHKeyAndExchange(SSLContext
*ctx
)
973 assert(ctx
->protocolSide
== SSL_ClientSide
);
974 if((ctx
->dhParamsPrime
.data
== NULL
) ||
975 (ctx
->dhParamsGenerator
.data
== NULL
) ||
976 (ctx
->dhPeerPublic
.data
== NULL
)) {
977 sslErrorLog("SSLGenClientDHKeyAndExchange: incomplete server params\n");
978 return errSSLProtocol
;
981 /* generate two keys */
983 ctx
->dhPrivate
= (CSSM_KEY
*)sslMalloc(sizeof(CSSM_KEY
));
984 ortn
= sslDhGenKeyPairClient(ctx
,
985 ctx
->dhParamsPrime
, ctx
->dhParamsGenerator
,
986 &pubKey
, ctx
->dhPrivate
);
988 sslFree(ctx
->dhPrivate
);
989 ctx
->dhPrivate
= NULL
;
993 /* do the exchange, size of prime */
994 ortn
= sslDhKeyExchange(ctx
, ctx
->dhParamsPrime
.length
* 8,
995 &ctx
->preMasterSecret
);
999 CSSM_TO_SSLBUF(&pubKey
.KeyData
, &ctx
->dhExchangePublic
);
1004 SSLEncodeDHanonServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
1006 OSStatus ortn
= noErr
;
1008 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
1009 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
1010 assert(ctx
->protocolSide
== SSL_ServerSide
);
1013 * Obtain D-H parameters (if we don't have them) and a key pair.
1015 ortn
= SSLGenServerDHParamsAndKey(ctx
);
1021 ctx
->dhParamsPrime
.length
+
1022 ctx
->dhParamsGenerator
.length
+ ctx
->dhExchangePublic
.length
;
1024 keyExch
.protocolVersion
= ctx
->negProtocolVersion
;
1025 keyExch
.contentType
= SSL_RecordTypeHandshake
;
1026 if ((ortn
= SSLAllocBuffer(keyExch
.contents
, length
+4, ctx
)) != 0)
1029 UInt8
*charPtr
= keyExch
.contents
.data
;
1030 *charPtr
++ = SSL_HdskServerKeyExchange
;
1031 charPtr
= SSLEncodeInt(charPtr
, length
, 3);
1033 /* encode prime, generator, our public key */
1034 return SSLEncodeDHKeyParams(ctx
, charPtr
);
1039 SSLDecodeDHanonServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
1041 OSStatus err
= noErr
;
1043 assert(ctx
->protocolSide
== SSL_ClientSide
);
1044 if (message
.length
< 6) {
1045 sslErrorLog("SSLDecodeDHanonServerKeyExchange error: msg len %u\n",
1046 (unsigned)message
.length
);
1047 return errSSLProtocol
;
1049 UInt8
*charPtr
= message
.data
;
1050 err
= SSLDecodeDHKeyParams(ctx
, charPtr
, message
.length
);
1052 if((message
.data
+ message
.length
) != charPtr
) {
1053 err
= errSSLProtocol
;
1060 SSLDecodeDHClientKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
1062 OSStatus ortn
= noErr
;
1063 unsigned int publicLen
;
1065 assert(ctx
->protocolSide
== SSL_ServerSide
);
1066 if(ctx
->dhParamsPrime
.data
== NULL
) {
1067 /* should never happen */
1069 return errSSLInternal
;
1072 /* this message simply contains the client's public DH key */
1073 UInt8
*charPtr
= keyExchange
.data
;
1074 publicLen
= SSLDecodeInt(charPtr
, 2);
1076 if((keyExchange
.length
!= publicLen
+ 2) ||
1077 (publicLen
> ctx
->dhParamsPrime
.length
)) {
1078 return errSSLProtocol
;
1080 SSLFreeBuffer(ctx
->dhPeerPublic
, ctx
); // allow reuse via renegotiation
1081 ortn
= SSLAllocBuffer(ctx
->dhPeerPublic
, publicLen
, ctx
);
1085 memmove(ctx
->dhPeerPublic
.data
, charPtr
, publicLen
);
1087 /* DH Key exchange, result --> premaster secret */
1088 SSLFreeBuffer(ctx
->preMasterSecret
, ctx
);
1089 ortn
= sslDhKeyExchange(ctx
, ctx
->dhParamsPrime
.length
* 8,
1090 &ctx
->preMasterSecret
);
1092 dumpBuf("server peer pub", ctx
->dhPeerPublic
);
1093 dumpBuf("server premaster", ctx
->preMasterSecret
);
1098 SSLEncodeDHClientKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
1100 unsigned int outputLen
;
1102 assert(ctx
->protocolSide
== SSL_ClientSide
);
1103 if ((err
= SSLGenClientDHKeyAndExchange(ctx
)) != 0)
1106 outputLen
= ctx
->dhExchangePublic
.length
+ 2;
1108 keyExchange
.contentType
= SSL_RecordTypeHandshake
;
1109 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
1110 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
1111 keyExchange
.protocolVersion
= ctx
->negProtocolVersion
;
1113 if ((err
= SSLAllocBuffer(keyExchange
.contents
,outputLen
+ 4,ctx
)) != 0)
1116 keyExchange
.contents
.data
[0] = SSL_HdskClientKeyExchange
;
1117 SSLEncodeInt(keyExchange
.contents
.data
+1,
1118 ctx
->dhExchangePublic
.length
+2, 3);
1120 SSLEncodeInt(keyExchange
.contents
.data
+4,
1121 ctx
->dhExchangePublic
.length
, 2);
1122 memcpy(keyExchange
.contents
.data
+6, ctx
->dhExchangePublic
.data
,
1123 ctx
->dhExchangePublic
.length
);
1125 dumpBuf("client pub key", ctx
->dhExchangePublic
);
1126 dumpBuf("client premaster", ctx
->preMasterSecret
);
1130 #endif /* APPLE_DH */
1133 #pragma mark *** Public Functions ***
1135 SSLEncodeServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
1138 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
)
1140 case SSL_RSA_EXPORT
:
1143 case SSL_DHE_RSA_EXPORT
:
1145 case SSL_DHE_DSS_EXPORT
:
1146 #endif /* APPLE_DH */
1147 if ((err
= SSLEncodeSignedServerKeyExchange(keyExch
, ctx
)) != 0)
1152 case SSL_DH_anon_EXPORT
:
1153 if ((err
= SSLEncodeDHanonServerKeyExchange(keyExch
, ctx
)) != 0)
1165 SSLProcessServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
1169 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1171 case SSL_RSA_EXPORT
:
1174 case SSL_DHE_RSA_EXPORT
:
1176 case SSL_DHE_DSS_EXPORT
:
1178 err
= SSLDecodeSignedServerKeyExchange(message
, ctx
);
1182 case SSL_DH_anon_EXPORT
:
1183 err
= SSLDecodeDHanonServerKeyExchange(message
, ctx
);
1195 SSLEncodeKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
1198 assert(ctx
->protocolSide
== SSL_ClientSide
);
1200 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1202 case SSL_RSA_EXPORT
:
1203 err
= SSLEncodeRSAKeyExchange(keyExchange
, ctx
);
1207 case SSL_DHE_RSA_EXPORT
:
1209 case SSL_DHE_DSS_EXPORT
:
1211 case SSL_DH_anon_EXPORT
:
1212 err
= SSLEncodeDHClientKeyExchange(keyExchange
, ctx
);
1223 SSLProcessKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
1226 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
)
1228 case SSL_RSA_EXPORT
:
1229 if ((err
= SSLDecodeRSAKeyExchange(keyExchange
, ctx
)) != 0)
1235 case SSL_DHE_DSS_EXPORT
:
1237 case SSL_DHE_RSA_EXPORT
:
1238 case SSL_DH_anon_EXPORT
:
1239 if ((err
= SSLDecodeDHClientKeyExchange(keyExchange
, ctx
)) != 0)
1251 SSLInitPendingCiphers(SSLContext
*ctx
)
1254 UInt8
*keyDataProgress
, *keyPtr
, *ivPtr
;
1256 CipherContext
*serverPending
, *clientPending
;
1260 ctx
->readPending
.macRef
= ctx
->selectedCipherSpec
->macAlgorithm
;
1261 ctx
->writePending
.macRef
= ctx
->selectedCipherSpec
->macAlgorithm
;
1262 ctx
->readPending
.symCipher
= ctx
->selectedCipherSpec
->cipher
;
1263 ctx
->writePending
.symCipher
= ctx
->selectedCipherSpec
->cipher
;
1264 ctx
->readPending
.sequenceNum
.high
= ctx
->readPending
.sequenceNum
.low
= 0;
1265 ctx
->writePending
.sequenceNum
.high
= ctx
->writePending
.sequenceNum
.low
= 0;
1267 keyDataLen
= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
+
1268 ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1269 if (ctx
->selectedCipherSpec
->isExportable
== NotExportable
)
1270 keyDataLen
+= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1271 keyDataLen
*= 2; /* two of everything */
1273 if ((err
= SSLAllocBuffer(key
, keyDataLen
, ctx
)) != 0)
1275 assert(ctx
->sslTslCalls
!= NULL
);
1276 if ((err
= ctx
->sslTslCalls
->generateKeyMaterial(key
, ctx
)) != 0)
1279 if (ctx
->protocolSide
== SSL_ServerSide
)
1280 { serverPending
= &ctx
->writePending
;
1281 clientPending
= &ctx
->readPending
;
1284 { serverPending
= &ctx
->readPending
;
1285 clientPending
= &ctx
->writePending
;
1288 keyDataProgress
= key
.data
;
1289 memcpy(clientPending
->macSecret
, keyDataProgress
,
1290 ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
);
1291 keyDataProgress
+= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
;
1292 memcpy(serverPending
->macSecret
, keyDataProgress
,
1293 ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
);
1294 keyDataProgress
+= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
;
1296 /* init the reusable-per-record MAC contexts */
1297 err
= ctx
->sslTslCalls
->initMac(clientPending
, ctx
);
1301 err
= ctx
->sslTslCalls
->initMac(serverPending
, ctx
);
1306 if (ctx
->selectedCipherSpec
->isExportable
== NotExportable
)
1307 { keyPtr
= keyDataProgress
;
1308 keyDataProgress
+= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1309 /* Skip server write key to get to IV */
1310 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1311 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(keyPtr
, ivPtr
,
1312 clientPending
, ctx
)) != 0)
1314 keyPtr
= keyDataProgress
;
1315 keyDataProgress
+= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1316 /* Skip client write IV to get to server write IV */
1317 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
->cipher
->ivSize
;
1318 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(keyPtr
, ivPtr
,
1319 serverPending
, ctx
)) != 0)
1323 UInt8 clientExportKey
[16], serverExportKey
[16],
1324 clientExportIV
[16], serverExportIV
[16];
1325 SSLBuffer clientWrite
, serverWrite
;
1326 SSLBuffer finalClientWrite
, finalServerWrite
;
1327 SSLBuffer finalClientIV
, finalServerIV
;
1329 assert(ctx
->selectedCipherSpec
->cipher
->keySize
<= 16);
1330 assert(ctx
->selectedCipherSpec
->cipher
->ivSize
<= 16);
1332 /* Inputs to generateExportKeyAndIv are clientRandom, serverRandom,
1333 * clientWriteKey, serverWriteKey. The first two are already present
1335 * Outputs are a key and IV for each of {server, client}.
1337 clientWrite
.data
= keyDataProgress
;
1338 clientWrite
.length
= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1339 serverWrite
.data
= keyDataProgress
+ clientWrite
.length
;
1340 serverWrite
.length
= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1341 finalClientWrite
.data
= clientExportKey
;
1342 finalServerWrite
.data
= serverExportKey
;
1343 finalClientIV
.data
= clientExportIV
;
1344 finalServerIV
.data
= serverExportIV
;
1345 finalClientWrite
.length
= 16;
1346 finalServerWrite
.length
= 16;
1347 /* these can be zero */
1348 finalClientIV
.length
= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1349 finalServerIV
.length
= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1351 assert(ctx
->sslTslCalls
!= NULL
);
1352 err
= ctx
->sslTslCalls
->generateExportKeyAndIv(ctx
, clientWrite
, serverWrite
,
1353 finalClientWrite
, finalServerWrite
, finalClientIV
, finalServerIV
);
1357 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(clientExportKey
,
1358 clientExportIV
, clientPending
, ctx
)) != 0)
1360 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(serverExportKey
,
1361 serverExportIV
, serverPending
, ctx
)) != 0)
1365 /* Ciphers are ready for use */
1366 ctx
->writePending
.ready
= 1;
1367 ctx
->readPending
.ready
= 1;
1369 /* Ciphers get swapped by sending or receiving a change cipher spec message */
1373 SSLFreeBuffer(key
, ctx
);