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 err
= sslGetPubKeyBits(ctx
,
198 SSLFreeBuffer(modulus
, ctx
);
199 SSLFreeBuffer(exponent
, ctx
);
203 if ((err
= SSLAllocBuffer(*keyParams
,
204 modulus
.length
+ exponent
.length
+ 4, ctx
)) != 0) {
207 charPtr
= keyParams
->data
;
208 charPtr
= SSLEncodeInt(charPtr
, modulus
.length
, 2);
209 memcpy(charPtr
, modulus
.data
, modulus
.length
);
210 charPtr
+= modulus
.length
;
211 charPtr
= SSLEncodeInt(charPtr
, exponent
.length
, 2);
212 memcpy(charPtr
, exponent
.data
, exponent
.length
);
214 /* these were mallocd by sslGetPubKeyBits() */
215 SSLFreeBuffer(modulus
, ctx
);
216 SSLFreeBuffer(exponent
, ctx
);
221 SSLEncodeRSAPremasterSecret(SSLContext
*ctx
)
222 { SSLBuffer randData
;
224 SSLProtocolVersion maxVersion
;
226 if ((err
= SSLAllocBuffer(ctx
->preMasterSecret
,
227 SSL_RSA_PREMASTER_SECRET_SIZE
, ctx
)) != 0)
230 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
231 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
232 sslGetMaxProtVersion(ctx
, &maxVersion
);
233 SSLEncodeInt(ctx
->preMasterSecret
.data
, maxVersion
, 2);
234 randData
.data
= ctx
->preMasterSecret
.data
+2;
235 randData
.length
= SSL_RSA_PREMASTER_SECRET_SIZE
- 2;
236 if ((err
= sslRand(ctx
, &randData
)) != 0)
242 * Generate a server key exchange message signed by our RSA or DSA private key.
245 SSLEncodeSignedServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
249 UInt8 hashes
[SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
];
250 SSLBuffer exchangeParams
,clientRandom
,serverRandom
,hashCtx
, hash
;
252 UInt32 dataToSignLen
;
258 assert(ctx
->protocolSide
== SSL_ServerSide
);
259 assert(ctx
->signingPubKey
!= NULL
);
260 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
261 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
262 exchangeParams
.data
= 0;
266 /* Set up parameter block to hash ==> exchangeParams */
267 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
271 * Parameter block = encryption public key.
272 * If app hasn't supplied a separate encryption cert, abort.
274 if(ctx
->encryptPubKey
== NULL
) {
275 sslErrorLog("RSAServerKeyExchange: no encrypt cert\n");
276 return errSSLBadConfiguration
;
278 err
= SSLEncodeRSAKeyParams(&exchangeParams
,
279 &ctx
->encryptPubKey
, ctx
);
284 case SSL_DHE_DSS_EXPORT
:
286 /* and fall through */
288 case SSL_DHE_RSA_EXPORT
:
291 * Parameter block = {prime, generator, public key}
292 * Obtain D-H parameters (if we don't have them) and a key pair.
294 err
= SSLGenServerDHParamsAndKey(ctx
);
298 UInt32 len
= ctx
->dhParamsPrime
.length
+
299 ctx
->dhParamsGenerator
.length
+
300 ctx
->dhExchangePublic
.length
+ 6 /* 3 length fields */;
301 err
= SSLAllocBuffer(exchangeParams
, len
, ctx
);
305 err
= SSLEncodeDHKeyParams(ctx
, exchangeParams
.data
);
308 #endif /* APPLE_DH */
310 /* shouldn't be here */
312 return errSSLInternal
;
318 /* cook up hash(es) for raw sign */
319 clientRandom
.data
= ctx
->clientRandom
;
320 clientRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
321 serverRandom
.data
= ctx
->serverRandom
;
322 serverRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
325 /* skip this if signing with DSA */
327 dataToSignLen
= SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
;
328 hash
.data
= &hashes
[0];
329 hash
.length
= SSL_MD5_DIGEST_LEN
;
331 if ((err
= ReadyHash(SSLHashMD5
, hashCtx
, ctx
)) != 0)
333 if ((err
= SSLHashMD5
.update(hashCtx
, clientRandom
)) != 0)
335 if ((err
= SSLHashMD5
.update(hashCtx
, serverRandom
)) != 0)
337 if ((err
= SSLHashMD5
.update(hashCtx
, exchangeParams
)) != 0)
339 if ((err
= SSLHashMD5
.final(hashCtx
, hash
)) != 0)
341 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
345 /* DSA - just use the SHA1 hash */
346 dataToSign
= &hashes
[SSL_MD5_DIGEST_LEN
];
347 dataToSignLen
= SSL_SHA1_DIGEST_LEN
;
349 hash
.data
= &hashes
[SSL_MD5_DIGEST_LEN
];
350 hash
.length
= SSL_SHA1_DIGEST_LEN
;
351 if ((err
= ReadyHash(SSLHashSHA1
, hashCtx
, ctx
)) != 0)
353 if ((err
= SSLHashSHA1
.update(hashCtx
, clientRandom
)) != 0)
355 if ((err
= SSLHashSHA1
.update(hashCtx
, serverRandom
)) != 0)
357 if ((err
= SSLHashSHA1
.update(hashCtx
, exchangeParams
)) != 0)
359 if ((err
= SSLHashSHA1
.final(hashCtx
, hash
)) != 0)
361 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
364 /* preallocate a buffer for signing */
365 err
= sslGetMaxSigSize(ctx
->signingPrivKey
, maxSigLen
);
369 err
= SSLAllocBuffer(signature
, maxSigLen
, ctx
);
374 err
= sslRawSign(ctx
,
377 dataToSign
, // one or two hashes
385 assert(actSigLen
<= maxSigLen
);
387 /* package it all up */
388 outputLen
= exchangeParams
.length
+ 2 + actSigLen
;
389 keyExch
.protocolVersion
= ctx
->negProtocolVersion
;
390 keyExch
.contentType
= SSL_RecordTypeHandshake
;
391 if ((err
= SSLAllocBuffer(keyExch
.contents
, outputLen
+4, ctx
)) != 0)
394 charPtr
= keyExch
.contents
.data
;
395 *charPtr
++ = SSL_HdskServerKeyExchange
;
396 charPtr
= SSLEncodeInt(charPtr
, outputLen
, 3);
398 memcpy(charPtr
, exchangeParams
.data
, exchangeParams
.length
);
399 charPtr
+= exchangeParams
.length
;
400 charPtr
= SSLEncodeInt(charPtr
, actSigLen
, 2);
401 memcpy(charPtr
, signature
.data
, actSigLen
);
402 assert((charPtr
+ actSigLen
) ==
403 (keyExch
.contents
.data
+ keyExch
.contents
.length
));
408 SSLFreeBuffer(hashCtx
, ctx
);
409 SSLFreeBuffer(exchangeParams
, ctx
);
410 SSLFreeBuffer(signature
, ctx
);
415 * Decode and verify a server key exchange message signed by server's
419 SSLDecodeSignedServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
422 SSLBuffer hashOut
, hashCtx
, clientRandom
, serverRandom
;
423 UInt16 modulusLen
, exponentLen
, signatureLen
;
424 UInt8
*modulus
, *exponent
, *signature
;
425 UInt8 hashes
[SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
];
426 SSLBuffer signedHashes
;
428 UInt32 dataToSignLen
;
431 assert(ctx
->protocolSide
== SSL_ClientSide
);
432 signedHashes
.data
= 0;
435 if (message
.length
< 2) {
436 sslErrorLog("SSLDecodeSignedServerKeyExchange: msg len error 1\n");
437 return errSSLProtocol
;
440 /* first extract the key-exchange-method-specific parameters */
441 UInt8
*charPtr
= message
.data
;
442 UInt8
*endCp
= charPtr
+ message
.length
;
443 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
446 modulusLen
= SSLDecodeInt(charPtr
, 2);
448 if((charPtr
+ modulusLen
) > endCp
) {
449 sslErrorLog("signedServerKeyExchange: msg len error 2\n");
450 return errSSLProtocol
;
453 charPtr
+= modulusLen
;
455 exponentLen
= SSLDecodeInt(charPtr
, 2);
457 if((charPtr
+ exponentLen
) > endCp
) {
458 sslErrorLog("signedServerKeyExchange: msg len error 3\n");
459 return errSSLProtocol
;
462 charPtr
+= exponentLen
;
466 case SSL_DHE_DSS_EXPORT
:
468 /* and fall through */
470 case SSL_DHE_RSA_EXPORT
:
471 err
= SSLDecodeDHKeyParams(ctx
, charPtr
, message
.length
);
476 #endif /* APPLE_DH */
479 return errSSLInternal
;
482 /* this is what's hashed */
483 SSLBuffer signedParams
;
484 signedParams
.data
= message
.data
;
485 signedParams
.length
= charPtr
- message
.data
;
487 signatureLen
= SSLDecodeInt(charPtr
, 2);
489 if((charPtr
+ signatureLen
) != endCp
) {
490 sslErrorLog("signedServerKeyExchange: msg len error 4\n");
491 return errSSLProtocol
;
495 clientRandom
.data
= ctx
->clientRandom
;
496 clientRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
497 serverRandom
.data
= ctx
->serverRandom
;
498 serverRandom
.length
= SSL_CLIENT_SRVR_RAND_SIZE
;
501 /* skip this if signing with DSA */
503 dataToSignLen
= SSL_SHA1_DIGEST_LEN
+ SSL_MD5_DIGEST_LEN
;
504 hashOut
.data
= hashes
;
505 hashOut
.length
= SSL_MD5_DIGEST_LEN
;
507 if ((err
= ReadyHash(SSLHashMD5
, hashCtx
, ctx
)) != 0)
509 if ((err
= SSLHashMD5
.update(hashCtx
, clientRandom
)) != 0)
511 if ((err
= SSLHashMD5
.update(hashCtx
, serverRandom
)) != 0)
513 if ((err
= SSLHashMD5
.update(hashCtx
, signedParams
)) != 0)
515 if ((err
= SSLHashMD5
.final(hashCtx
, hashOut
)) != 0)
519 /* DSA - just use the SHA1 hash */
520 dataToSign
= &hashes
[SSL_MD5_DIGEST_LEN
];
521 dataToSignLen
= SSL_SHA1_DIGEST_LEN
;
523 hashOut
.data
= hashes
+ SSL_MD5_DIGEST_LEN
;
524 hashOut
.length
= SSL_SHA1_DIGEST_LEN
;
525 if ((err
= SSLFreeBuffer(hashCtx
, ctx
)) != 0)
528 if ((err
= ReadyHash(SSLHashSHA1
, hashCtx
, ctx
)) != 0)
530 if ((err
= SSLHashSHA1
.update(hashCtx
, clientRandom
)) != 0)
532 if ((err
= SSLHashSHA1
.update(hashCtx
, serverRandom
)) != 0)
534 if ((err
= SSLHashSHA1
.update(hashCtx
, signedParams
)) != 0)
536 if ((err
= SSLHashSHA1
.final(hashCtx
, hashOut
)) != 0)
539 err
= sslRawVerify(ctx
,
542 dataToSign
, /* plaintext */
543 dataToSignLen
, /* plaintext length */
547 sslErrorLog("SSLDecodeSignedServerKeyExchange: sslRawVerify "
548 "returned %d\n", (int)err
);
552 /* Signature matches; now replace server key with new key */
553 switch(ctx
->selectedCipherSpec
->keyExchangeMethod
) {
560 /* first free existing peerKey */
561 sslFreeKey(ctx
->peerPubKeyCsp
,
563 NULL
); /* no KCItem */
565 /* and cook up a new one from raw bits */
566 modBuf
.data
= modulus
;
567 modBuf
.length
= modulusLen
;
568 expBuf
.data
= exponent
;
569 expBuf
.length
= exponentLen
;
570 err
= sslGetPubKeyFromBits(ctx
,
574 &ctx
->peerPubKeyCsp
);
578 case SSL_DHE_RSA_EXPORT
:
580 case SSL_DHE_DSS_EXPORT
:
581 break; /* handled above */
583 assert(0); /* handled above */
586 SSLFreeBuffer(signedHashes
, ctx
);
587 SSLFreeBuffer(hashCtx
, ctx
);
592 SSLDecodeRSAKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
594 UInt32 outputLen
, localKeyModulusLen
;
596 SSLProtocolVersion version
;
597 Boolean useEncryptKey
= false;
601 /* different key names, also need CSP handle */
602 CSSM_CSP_HANDLE cspHand
;
604 assert(ctx
->protocolSide
== SSL_ServerSide
);
606 #if SSL_SERVER_KEYEXCH_HACK
608 * the way we work with Netscape.
609 * FIXME - maybe we should *require* an encryptPrivKey in this
612 if((ctx
->selectedCipherSpec
->keyExchangeMethod
== SSL_RSA_EXPORT
) &&
613 (ctx
->encryptPrivKey
!= NULL
)) {
614 useEncryptKey
= true;
617 #else /* !SSL_SERVER_KEYEXCH_HACK */
618 /* The "correct" way, I think, which doesn't work with Netscape */
619 if (ctx
->encryptPrivKey
) {
620 useEncryptKey
= true;
622 #endif /* SSL_SERVER_KEYEXCH_HACK */
624 key
= &ctx
->encryptPrivKey
;
625 cspHand
= ctx
->encryptKeyCsp
;
628 key
= &ctx
->signingPrivKey
;
629 cspHand
= ctx
->signingKeyCsp
;
632 localKeyModulusLen
= sslKeyLengthInBytes(*key
);
635 * We have to tolerate incoming key exchange msgs with and without the
636 * two-byte "encrypted length" field.
638 if (keyExchange
.length
== localKeyModulusLen
) {
639 /* no length encoded */
640 src
= keyExchange
.data
;
642 else if((keyExchange
.length
== (localKeyModulusLen
+ 2)) &&
643 (ctx
->negProtocolVersion
>= TLS_Version_1_0
)) {
644 /* TLS only - skip the length bytes */
645 src
= keyExchange
.data
+ 2;
648 sslErrorLog("SSLDecodeRSAKeyExchange: length error (exp %u got %u)\n",
649 (unsigned)localKeyModulusLen
, (unsigned)keyExchange
.length
);
650 return errSSLProtocol
;
652 err
= SSLAllocBuffer(ctx
->preMasterSecret
, SSL_RSA_PREMASTER_SECRET_SIZE
, ctx
);
658 * From this point on, to defend against the Bleichenbacher attack
659 * and its Klima-Pokorny-Rosa variant, any errors we detect are *not*
660 * reported to the caller or the peer. If we detect any error during
661 * decryption (e.g., bad PKCS1 padding) or in the testing of the version
662 * number in the premaster secret, we proceed by generating a random
663 * premaster secret, with the correct version number, and tell our caller
664 * that everything is fine. This session will fail as soon as the
665 * finished messages are sent, since we will be using a bogus premaster
666 * secret (and hence bogus session and MAC keys). Meanwhile we have
667 * not provided any side channel information relating to the cause of
670 * See http://eprint.iacr.org/2003/052/ for more info.
672 err
= sslRsaDecrypt(ctx
,
676 localKeyModulusLen
, // ciphertext len
677 ctx
->preMasterSecret
.data
,
678 SSL_RSA_PREMASTER_SECRET_SIZE
, // plaintext buf available
682 /* possible Bleichenbacher attack */
683 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: RSA decrypt fail");
685 else if(outputLen
!= SSL_RSA_PREMASTER_SECRET_SIZE
) {
686 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: premaster secret size error");
687 err
= errSSLProtocol
; // not passed back to caller
692 * Two legal values here - the one we actually negotiated (which is
693 * technically incorrect but not uncommon), and the one the client
694 * sent as its preferred version in the client hello msg.
696 version
= (SSLProtocolVersion
)SSLDecodeInt(ctx
->preMasterSecret
.data
, 2);
697 if((version
!= ctx
->negProtocolVersion
) &&
698 (version
!= ctx
->clientReqProtocol
)) {
699 /* possible Klima-Pokorny-Rosa attack */
700 sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: version error");
701 err
= errSSLProtocol
;
706 * Obfuscate failures for defense against Bleichenbacher and
707 * Klima-Pokorny-Rosa attacks.
709 SSLEncodeInt(ctx
->preMasterSecret
.data
, ctx
->negProtocolVersion
, 2);
711 tmpBuf
.data
= ctx
->preMasterSecret
.data
+ 2;
712 tmpBuf
.length
= SSL_RSA_PREMASTER_SECRET_SIZE
- 2;
713 /* must ignore failures here */
714 sslRand(ctx
, &tmpBuf
);
717 /* in any case, save premaster secret (good or bogus) and proceed */
722 SSLEncodeRSAKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
724 UInt32 outputLen
, peerKeyModulusLen
;
727 bool encodeLen
= false;
729 assert(ctx
->protocolSide
== SSL_ClientSide
);
730 if ((err
= SSLEncodeRSAPremasterSecret(ctx
)) != 0)
733 keyExchange
.contentType
= SSL_RecordTypeHandshake
;
734 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
735 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
736 keyExchange
.protocolVersion
= ctx
->negProtocolVersion
;
738 peerKeyModulusLen
= sslKeyLengthInBytes(ctx
->peerPubKey
);
739 bufLen
= peerKeyModulusLen
+ 4;
740 #if RSA_CLIENT_KEY_ADD_LENGTH
741 if(ctx
->negProtocolVersion
>= TLS_Version_1_0
) {
746 if ((err
= SSLAllocBuffer(keyExchange
.contents
,
751 dst
= keyExchange
.contents
.data
+ 4;
755 keyExchange
.contents
.data
[0] = SSL_HdskClientKeyExchange
;
757 /* this is the record payload length */
758 SSLEncodeInt(keyExchange
.contents
.data
+ 1, bufLen
- 4, 3);
760 /* the length of the encrypted pre_master_secret */
761 SSLEncodeInt(keyExchange
.contents
.data
+ 4,
762 peerKeyModulusLen
, 2);
764 err
= sslRsaEncrypt(ctx
,
766 /* FIXME - maybe this should be ctx->cspHand */
768 ctx
->preMasterSecret
.data
,
769 SSL_RSA_PREMASTER_SECRET_SIZE
,
777 assert(outputLen
== encodeLen
?
778 keyExchange
.contents
.length
- 6 :
779 keyExchange
.contents
.length
- 4 );
788 #pragma mark *** Diffie-Hellman key exchange ***
791 * Diffie-Hellman setup, server side. On successful return, the
792 * following SSLContext members are valid:
800 SSLGenServerDHParamsAndKey(
804 assert(ctx
->protocolSide
== SSL_ServerSide
);
807 * Obtain D-H parameters if we don't have them.
809 if(ctx
->dhParamsPrime
.data
== NULL
) {
810 assert(ctx
->dhParamsGenerator
.data
== NULL
);
811 const SSLBuffer
&pr
= serverDhParams().prime();
812 ortn
= SSLCopyBuffer(pr
, ctx
->dhParamsPrime
);
816 const SSLBuffer
&gen
= serverDhParams().generator();
817 ortn
= SSLCopyBuffer(gen
, ctx
->dhParamsGenerator
);
821 const SSLBuffer
&block
= serverDhParams().paramBlock();
822 ortn
= SSLCopyBuffer(block
, ctx
->dhParamsEncoded
);
828 /* generate per-session D-H key pair */
829 sslFreeKey(ctx
->cspHand
, &ctx
->dhPrivate
, NULL
);
830 SSLFreeBuffer(ctx
->dhExchangePublic
, ctx
);
831 ctx
->dhPrivate
= (CSSM_KEY
*)sslMalloc(sizeof(CSSM_KEY
));
833 ortn
= sslDhGenerateKeyPair(ctx
,
834 ctx
->dhParamsEncoded
,
835 ctx
->dhParamsPrime
.length
* 8,
836 &pubKey
, ctx
->dhPrivate
);
840 CSSM_TO_SSLBUF(&pubKey
.KeyData
, &ctx
->dhExchangePublic
);
845 * Encode DH params and public key in caller-supplied buffer.
848 SSLEncodeDHKeyParams(
852 assert(ctx
->protocolSide
== SSL_ServerSide
);
853 assert(ctx
->dhParamsPrime
.data
!= NULL
);
854 assert(ctx
->dhParamsGenerator
.data
!= NULL
);
855 assert(ctx
->dhExchangePublic
.data
!= NULL
);
857 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhParamsPrime
.length
, 2);
858 memcpy(charPtr
, ctx
->dhParamsPrime
.data
, ctx
->dhParamsPrime
.length
);
859 charPtr
+= ctx
->dhParamsPrime
.length
;
861 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhParamsGenerator
.length
, 2);
862 memcpy(charPtr
, ctx
->dhParamsGenerator
.data
,
863 ctx
->dhParamsGenerator
.length
);
864 charPtr
+= ctx
->dhParamsGenerator
.length
;
866 charPtr
= SSLEncodeInt(charPtr
, ctx
->dhExchangePublic
.length
, 2);
867 memcpy(charPtr
, ctx
->dhExchangePublic
.data
,
868 ctx
->dhExchangePublic
.length
);
870 dumpBuf("server prime", ctx
->dhParamsPrime
);
871 dumpBuf("server generator", ctx
->dhParamsGenerator
);
872 dumpBuf("server pub key", ctx
->dhExchangePublic
);
877 * Decode DH params and server public key.
880 SSLDecodeDHKeyParams(
882 UInt8
*&charPtr
, // IN/OUT
885 OSStatus err
= noErr
;
887 assert(ctx
->protocolSide
== SSL_ClientSide
);
888 UInt8
*endCp
= charPtr
+ length
;
890 /* Allow reuse via renegotiation */
891 SSLFreeBuffer(ctx
->dhParamsPrime
, ctx
);
892 SSLFreeBuffer(ctx
->dhParamsGenerator
, ctx
);
893 SSLFreeBuffer(ctx
->dhPeerPublic
, ctx
);
895 /* Prime, with a two-byte length */
896 UInt32 len
= SSLDecodeInt(charPtr
, 2);
898 if((charPtr
+ len
) > endCp
) {
899 return errSSLProtocol
;
901 err
= SSLAllocBuffer(ctx
->dhParamsPrime
, len
, ctx
);
905 memmove(ctx
->dhParamsPrime
.data
, charPtr
, len
);
908 /* Generator, with a two-byte length */
909 len
= SSLDecodeInt(charPtr
, 2);
911 if((charPtr
+ len
) > endCp
) {
912 return errSSLProtocol
;
914 err
= SSLAllocBuffer(ctx
->dhParamsGenerator
, len
, ctx
);
918 memmove(ctx
->dhParamsGenerator
.data
, charPtr
, len
);
921 /* peer public key, with a two-byte length */
922 len
= SSLDecodeInt(charPtr
, 2);
924 err
= SSLAllocBuffer(ctx
->dhPeerPublic
, len
, ctx
);
928 memmove(ctx
->dhPeerPublic
.data
, charPtr
, len
);
931 dumpBuf("client peer pub", ctx
->dhPeerPublic
);
932 dumpBuf("client prime", ctx
->dhParamsPrime
);
933 dumpBuf("client generator", ctx
->dhParamsGenerator
);
939 * Given the server's Diffie-Hellman parameters, generate our
940 * own DH key pair, and perform key exchange using the server's
941 * public key and our private key. The result is the premaster
944 * SSLContext members valid on entry:
949 * SSLContext members valid on successful return:
955 SSLGenClientDHKeyAndExchange(SSLContext
*ctx
)
959 assert(ctx
->protocolSide
== SSL_ClientSide
);
960 if((ctx
->dhParamsPrime
.data
== NULL
) ||
961 (ctx
->dhParamsGenerator
.data
== NULL
) ||
962 (ctx
->dhPeerPublic
.data
== NULL
)) {
963 sslErrorLog("SSLGenClientDHKeyAndExchange: incomplete server params\n");
964 return errSSLProtocol
;
967 /* generate two keys */
969 ctx
->dhPrivate
= (CSSM_KEY
*)sslMalloc(sizeof(CSSM_KEY
));
970 ortn
= sslDhGenKeyPairClient(ctx
,
971 ctx
->dhParamsPrime
, ctx
->dhParamsGenerator
,
972 &pubKey
, ctx
->dhPrivate
);
974 sslFree(ctx
->dhPrivate
);
975 ctx
->dhPrivate
= NULL
;
979 /* do the exchange, size of prime */
980 ortn
= sslDhKeyExchange(ctx
, ctx
->dhParamsPrime
.length
* 8,
981 &ctx
->preMasterSecret
);
985 CSSM_TO_SSLBUF(&pubKey
.KeyData
, &ctx
->dhExchangePublic
);
990 SSLEncodeDHanonServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
992 OSStatus ortn
= noErr
;
994 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
995 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
996 assert(ctx
->protocolSide
== SSL_ServerSide
);
999 * Obtain D-H parameters (if we don't have them) and a key pair.
1001 ortn
= SSLGenServerDHParamsAndKey(ctx
);
1007 ctx
->dhParamsPrime
.length
+
1008 ctx
->dhParamsGenerator
.length
+ ctx
->dhExchangePublic
.length
;
1010 keyExch
.protocolVersion
= ctx
->negProtocolVersion
;
1011 keyExch
.contentType
= SSL_RecordTypeHandshake
;
1012 if ((ortn
= SSLAllocBuffer(keyExch
.contents
, length
+4, ctx
)) != 0)
1015 UInt8
*charPtr
= keyExch
.contents
.data
;
1016 *charPtr
++ = SSL_HdskServerKeyExchange
;
1017 charPtr
= SSLEncodeInt(charPtr
, length
, 3);
1019 /* encode prime, generator, our public key */
1020 return SSLEncodeDHKeyParams(ctx
, charPtr
);
1025 SSLDecodeDHanonServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
1027 OSStatus err
= noErr
;
1029 assert(ctx
->protocolSide
== SSL_ClientSide
);
1030 if (message
.length
< 6) {
1031 sslErrorLog("SSLDecodeDHanonServerKeyExchange error: msg len %u\n",
1032 (unsigned)message
.length
);
1033 return errSSLProtocol
;
1035 UInt8
*charPtr
= message
.data
;
1036 err
= SSLDecodeDHKeyParams(ctx
, charPtr
, message
.length
);
1038 if((message
.data
+ message
.length
) != charPtr
) {
1039 err
= errSSLProtocol
;
1046 SSLDecodeDHClientKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
1048 OSStatus ortn
= noErr
;
1049 unsigned int publicLen
;
1051 assert(ctx
->protocolSide
== SSL_ServerSide
);
1052 if(ctx
->dhParamsPrime
.data
== NULL
) {
1053 /* should never happen */
1055 return errSSLInternal
;
1058 /* this message simply contains the client's public DH key */
1059 UInt8
*charPtr
= keyExchange
.data
;
1060 publicLen
= SSLDecodeInt(charPtr
, 2);
1062 if((keyExchange
.length
!= publicLen
+ 2) ||
1063 (publicLen
> ctx
->dhParamsPrime
.length
)) {
1064 return errSSLProtocol
;
1066 SSLFreeBuffer(ctx
->dhPeerPublic
, ctx
); // allow reuse via renegotiation
1067 ortn
= SSLAllocBuffer(ctx
->dhPeerPublic
, publicLen
, ctx
);
1071 memmove(ctx
->dhPeerPublic
.data
, charPtr
, publicLen
);
1073 /* DH Key exchange, result --> premaster secret */
1074 SSLFreeBuffer(ctx
->preMasterSecret
, ctx
);
1075 ortn
= sslDhKeyExchange(ctx
, ctx
->dhParamsPrime
.length
* 8,
1076 &ctx
->preMasterSecret
);
1078 dumpBuf("server peer pub", ctx
->dhPeerPublic
);
1079 dumpBuf("server premaster", ctx
->preMasterSecret
);
1084 SSLEncodeDHClientKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
1086 unsigned int outputLen
;
1088 assert(ctx
->protocolSide
== SSL_ClientSide
);
1089 if ((err
= SSLGenClientDHKeyAndExchange(ctx
)) != 0)
1092 outputLen
= ctx
->dhExchangePublic
.length
+ 2;
1094 keyExchange
.contentType
= SSL_RecordTypeHandshake
;
1095 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
1096 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
1097 keyExchange
.protocolVersion
= ctx
->negProtocolVersion
;
1099 if ((err
= SSLAllocBuffer(keyExchange
.contents
,outputLen
+ 4,ctx
)) != 0)
1102 keyExchange
.contents
.data
[0] = SSL_HdskClientKeyExchange
;
1103 SSLEncodeInt(keyExchange
.contents
.data
+1,
1104 ctx
->dhExchangePublic
.length
+2, 3);
1106 SSLEncodeInt(keyExchange
.contents
.data
+4,
1107 ctx
->dhExchangePublic
.length
, 2);
1108 memcpy(keyExchange
.contents
.data
+6, ctx
->dhExchangePublic
.data
,
1109 ctx
->dhExchangePublic
.length
);
1111 dumpBuf("client pub key", ctx
->dhExchangePublic
);
1112 dumpBuf("client premaster", ctx
->preMasterSecret
);
1116 #endif /* APPLE_DH */
1119 #pragma mark *** Public Functions ***
1121 SSLEncodeServerKeyExchange(SSLRecord
&keyExch
, SSLContext
*ctx
)
1124 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
)
1126 case SSL_RSA_EXPORT
:
1129 case SSL_DHE_RSA_EXPORT
:
1131 case SSL_DHE_DSS_EXPORT
:
1132 #endif /* APPLE_DH */
1133 if ((err
= SSLEncodeSignedServerKeyExchange(keyExch
, ctx
)) != 0)
1138 case SSL_DH_anon_EXPORT
:
1139 if ((err
= SSLEncodeDHanonServerKeyExchange(keyExch
, ctx
)) != 0)
1151 SSLProcessServerKeyExchange(SSLBuffer message
, SSLContext
*ctx
)
1155 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1157 case SSL_RSA_EXPORT
:
1160 case SSL_DHE_RSA_EXPORT
:
1162 case SSL_DHE_DSS_EXPORT
:
1164 err
= SSLDecodeSignedServerKeyExchange(message
, ctx
);
1168 case SSL_DH_anon_EXPORT
:
1169 err
= SSLDecodeDHanonServerKeyExchange(message
, ctx
);
1181 SSLEncodeKeyExchange(SSLRecord
&keyExchange
, SSLContext
*ctx
)
1184 assert(ctx
->protocolSide
== SSL_ClientSide
);
1186 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
) {
1188 case SSL_RSA_EXPORT
:
1189 err
= SSLEncodeRSAKeyExchange(keyExchange
, ctx
);
1193 case SSL_DHE_RSA_EXPORT
:
1195 case SSL_DHE_DSS_EXPORT
:
1197 case SSL_DH_anon_EXPORT
:
1198 err
= SSLEncodeDHClientKeyExchange(keyExchange
, ctx
);
1209 SSLProcessKeyExchange(SSLBuffer keyExchange
, SSLContext
*ctx
)
1212 switch (ctx
->selectedCipherSpec
->keyExchangeMethod
)
1214 case SSL_RSA_EXPORT
:
1215 if ((err
= SSLDecodeRSAKeyExchange(keyExchange
, ctx
)) != 0)
1221 case SSL_DHE_DSS_EXPORT
:
1223 case SSL_DHE_RSA_EXPORT
:
1224 case SSL_DH_anon_EXPORT
:
1225 if ((err
= SSLDecodeDHClientKeyExchange(keyExchange
, ctx
)) != 0)
1237 SSLInitPendingCiphers(SSLContext
*ctx
)
1240 UInt8
*keyDataProgress
, *keyPtr
, *ivPtr
;
1242 CipherContext
*serverPending
, *clientPending
;
1246 ctx
->readPending
.macRef
= ctx
->selectedCipherSpec
->macAlgorithm
;
1247 ctx
->writePending
.macRef
= ctx
->selectedCipherSpec
->macAlgorithm
;
1248 ctx
->readPending
.symCipher
= ctx
->selectedCipherSpec
->cipher
;
1249 ctx
->writePending
.symCipher
= ctx
->selectedCipherSpec
->cipher
;
1250 ctx
->readPending
.sequenceNum
.high
= ctx
->readPending
.sequenceNum
.low
= 0;
1251 ctx
->writePending
.sequenceNum
.high
= ctx
->writePending
.sequenceNum
.low
= 0;
1253 keyDataLen
= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
+
1254 ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1255 if (ctx
->selectedCipherSpec
->isExportable
== NotExportable
)
1256 keyDataLen
+= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1257 keyDataLen
*= 2; /* two of everything */
1259 if ((err
= SSLAllocBuffer(key
, keyDataLen
, ctx
)) != 0)
1261 assert(ctx
->sslTslCalls
!= NULL
);
1262 if ((err
= ctx
->sslTslCalls
->generateKeyMaterial(key
, ctx
)) != 0)
1265 if (ctx
->protocolSide
== SSL_ServerSide
)
1266 { serverPending
= &ctx
->writePending
;
1267 clientPending
= &ctx
->readPending
;
1270 { serverPending
= &ctx
->readPending
;
1271 clientPending
= &ctx
->writePending
;
1274 keyDataProgress
= key
.data
;
1275 memcpy(clientPending
->macSecret
, keyDataProgress
,
1276 ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
);
1277 keyDataProgress
+= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
;
1278 memcpy(serverPending
->macSecret
, keyDataProgress
,
1279 ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
);
1280 keyDataProgress
+= ctx
->selectedCipherSpec
->macAlgorithm
->hash
->digestSize
;
1282 /* init the reusable-per-record MAC contexts */
1283 err
= ctx
->sslTslCalls
->initMac(clientPending
, ctx
);
1287 err
= ctx
->sslTslCalls
->initMac(serverPending
, ctx
);
1292 if (ctx
->selectedCipherSpec
->isExportable
== NotExportable
)
1293 { keyPtr
= keyDataProgress
;
1294 keyDataProgress
+= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1295 /* Skip server write key to get to IV */
1296 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1297 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(keyPtr
, ivPtr
,
1298 clientPending
, ctx
)) != 0)
1300 keyPtr
= keyDataProgress
;
1301 keyDataProgress
+= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1302 /* Skip client write IV to get to server write IV */
1303 ivPtr
= keyDataProgress
+ ctx
->selectedCipherSpec
->cipher
->ivSize
;
1304 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(keyPtr
, ivPtr
,
1305 serverPending
, ctx
)) != 0)
1309 UInt8 clientExportKey
[16], serverExportKey
[16],
1310 clientExportIV
[16], serverExportIV
[16];
1311 SSLBuffer clientWrite
, serverWrite
;
1312 SSLBuffer finalClientWrite
, finalServerWrite
;
1313 SSLBuffer finalClientIV
, finalServerIV
;
1315 assert(ctx
->selectedCipherSpec
->cipher
->keySize
<= 16);
1316 assert(ctx
->selectedCipherSpec
->cipher
->ivSize
<= 16);
1318 /* Inputs to generateExportKeyAndIv are clientRandom, serverRandom,
1319 * clientWriteKey, serverWriteKey. The first two are already present
1321 * Outputs are a key and IV for each of {server, client}.
1323 clientWrite
.data
= keyDataProgress
;
1324 clientWrite
.length
= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1325 serverWrite
.data
= keyDataProgress
+ clientWrite
.length
;
1326 serverWrite
.length
= ctx
->selectedCipherSpec
->cipher
->secretKeySize
;
1327 finalClientWrite
.data
= clientExportKey
;
1328 finalServerWrite
.data
= serverExportKey
;
1329 finalClientIV
.data
= clientExportIV
;
1330 finalServerIV
.data
= serverExportIV
;
1331 finalClientWrite
.length
= 16;
1332 finalServerWrite
.length
= 16;
1333 /* these can be zero */
1334 finalClientIV
.length
= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1335 finalServerIV
.length
= ctx
->selectedCipherSpec
->cipher
->ivSize
;
1337 assert(ctx
->sslTslCalls
!= NULL
);
1338 err
= ctx
->sslTslCalls
->generateExportKeyAndIv(ctx
, clientWrite
, serverWrite
,
1339 finalClientWrite
, finalServerWrite
, finalClientIV
, finalServerIV
);
1343 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(clientExportKey
,
1344 clientExportIV
, clientPending
, ctx
)) != 0)
1346 if ((err
= ctx
->selectedCipherSpec
->cipher
->initialize(serverExportKey
,
1347 serverExportIV
, serverPending
, ctx
)) != 0)
1351 /* Ciphers are ready for use */
1352 ctx
->writePending
.ready
= 1;
1353 ctx
->readPending
.ready
= 1;
1355 /* Ciphers get swapped by sending or receiving a change cipher spec message */
1359 SSLFreeBuffer(key
, ctx
);