]>
git.saurik.com Git - apple/security.git/blob - SecureTransport/sslCert.cpp
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.
22 Contains: certificate request/verify messages
24 Written by: Doug Mitchell
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
29 #include "sslContext.h"
30 #include "sslHandshake.h"
31 #include "sslMemory.h"
32 #include "sslAlertMessage.h"
35 #include "sslDigests.h"
36 #include "appleCdsa.h"
42 SSLEncodeCertificate(SSLRecord
&certificate
, SSLContext
*ctx
)
50 * TBD: for client side, match Match DER-encoded acceptable DN list
51 * (ctx->acceptableDNList) to one of our certs. For now we just send
52 * what we have since we don't support multiple certs.
54 * Note this can be called with localCert==0 for client seide in TLS1;
55 * in that case we send an empty cert msg.
57 cert
= ctx
->localCert
;
58 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
59 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
60 assert((cert
!= NULL
) || (ctx
->negProtocolVersion
== TLS_Version_1_0
));
64 { totalLength
+= 3 + cert
->derCert
.length
; /* 3 for encoded length field */
69 certificate
.contentType
= SSL_RecordTypeHandshake
;
70 certificate
.protocolVersion
= ctx
->negProtocolVersion
;
71 if ((err
= SSLAllocBuffer(certificate
.contents
, totalLength
+ 7, ctx
)) != 0)
74 charPtr
= certificate
.contents
.data
;
75 *charPtr
++ = SSL_HdskCert
;
76 charPtr
= SSLEncodeInt(charPtr
, totalLength
+3, 3); /* Handshake message length */
77 charPtr
= SSLEncodeInt(charPtr
, totalLength
, 3); /* Vector length */
79 /* Root cert is first in the linked list, but has to go last,
80 * so walk list backwards */
81 for (i
= 0; i
< certCount
; ++i
)
82 { cert
= ctx
->localCert
;
83 for (j
= i
+1; j
< certCount
; ++j
)
85 charPtr
= SSLEncodeInt(charPtr
, cert
->derCert
.length
, 3);
86 memcpy(charPtr
, cert
->derCert
.data
, cert
->derCert
.length
);
87 charPtr
+= cert
->derCert
.length
;
90 assert(charPtr
== certificate
.contents
.data
+ certificate
.contents
.length
);
92 if ((ctx
->protocolSide
== SSL_ClientSide
) && (ctx
->localCert
)) {
93 /* this tells us to send a CertificateVerify msg after the
94 * client key exchange. We skip the cert vfy if we just
95 * sent an empty cert msg (i.e., we were asked for a cert
96 * but we don't have one). */
98 assert(ctx
->clientCertState
== kSSLClientCertRequested
);
99 assert(ctx
->certRequested
);
100 ctx
->clientCertState
= kSSLClientCertSent
;
106 SSLProcessCertificate(SSLBuffer message
, SSLContext
*ctx
)
108 UInt32 listLen
, certLen
;
110 SSLCertificate
*cert
;
113 listLen
= SSLDecodeInt(p
,3);
115 if (listLen
+ 3 != message
.length
) {
116 sslErrorLog("SSLProcessCertificate: length decode error 1\n");
117 return errSSLProtocol
;
121 { certLen
= SSLDecodeInt(p
,3);
123 if (listLen
< certLen
+ 3) {
124 sslErrorLog("SSLProcessCertificate: length decode error 2\n");
125 return errSSLProtocol
;
127 cert
= (SSLCertificate
*)sslMalloc(sizeof(SSLCertificate
));
131 if ((err
= SSLAllocBuffer(cert
->derCert
, certLen
, ctx
)) != 0)
135 memcpy(cert
->derCert
.data
, p
, certLen
);
137 cert
->next
= ctx
->peerCert
; /* Insert backwards; root cert
138 * will be first in linked list */
139 ctx
->peerCert
= cert
;
140 listLen
-= 3+certLen
;
142 assert(p
== message
.data
+ message
.length
&& listLen
== 0);
144 if (ctx
->peerCert
== 0) {
145 /* this *might* be OK... */
146 if((ctx
->protocolSide
== SSL_ServerSide
) &&
147 (ctx
->clientAuth
!= kAlwaysAuthenticate
)) {
149 * we tried to authenticate, client doesn't have a cert, and
150 * app doesn't require it. OK.
155 AlertDescription desc
;
156 if(ctx
->negProtocolVersion
== SSL_Version_3_0
) {
157 /* this one's for SSL3 only */
158 desc
= SSL_AlertBadCert
;
161 desc
= SSL_AlertCertUnknown
;
163 SSLFatalSessionAlert(desc
, ctx
);
164 return errSSLXCertChainInvalid
;
167 if((err
= sslVerifyCertChain(ctx
, *ctx
->peerCert
)) != 0) {
168 AlertDescription desc
;
170 case errSSLUnknownRootCert
:
171 case errSSLNoRootCert
:
172 desc
= SSL_AlertUnknownCA
;
174 case errSSLCertExpired
:
175 case errSSLCertNotYetValid
:
176 desc
= SSL_AlertCertExpired
;
178 case errSSLXCertChainInvalid
:
180 desc
= SSL_AlertCertUnknown
;
183 SSLFatalSessionAlert(desc
, ctx
);
187 /* peer's certificate is the last one in the chain */
188 cert
= ctx
->peerCert
;
189 while (cert
->next
!= 0)
191 /* Convert its public key to CDSA format */
192 if ((err
= sslPubKeyFromCert(ctx
,
195 &ctx
->peerPubKeyCsp
)) != 0)
202 SSLEncodeCertificateRequest(SSLRecord
&request
, SSLContext
*ctx
)
205 UInt32 dnListLen
, msgLen
;
209 assert(ctx
->protocolSide
== SSL_ServerSide
);
211 dn
= ctx
->acceptableDNList
;
213 { dnListLen
+= 2 + dn
->derDN
.length
;
216 msgLen
= 1 + 1 + 2 + dnListLen
;
218 request
.contentType
= SSL_RecordTypeHandshake
;
219 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
220 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
221 request
.protocolVersion
= ctx
->negProtocolVersion
;
222 if ((err
= SSLAllocBuffer(request
.contents
, msgLen
+ 4, ctx
)) != 0)
225 charPtr
= request
.contents
.data
;
226 *charPtr
++ = SSL_HdskCertRequest
;
227 charPtr
= SSLEncodeInt(charPtr
, msgLen
, 3);
229 *charPtr
++ = 1; /* one cert type */
230 *charPtr
++ = 1; /* RSA-sign type */
231 charPtr
= SSLEncodeInt(charPtr
, dnListLen
, 2);
232 dn
= ctx
->acceptableDNList
;
234 { charPtr
= SSLEncodeInt(charPtr
, dn
->derDN
.length
, 2);
235 memcpy(charPtr
, dn
->derDN
.data
, dn
->derDN
.length
);
236 charPtr
+= dn
->derDN
.length
;
240 assert(charPtr
== request
.contents
.data
+ request
.contents
.length
);
245 SSLProcessCertificateRequest(SSLBuffer message
, SSLContext
*ctx
)
252 * Cert request only happens in during client authentication, which
253 * we don't do. We will however take this handshake msg and do
254 * nothing with the enclosed DNList. We'll send a client cert
255 * if we have one but we don't do any DNList compare.
257 if (message
.length
< 3) {
258 sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n");
259 return errSSLProtocol
;
261 charPtr
= message
.data
;
262 typeCount
= *charPtr
++;
263 if (typeCount
< 1 || message
.length
< 3 + typeCount
) {
264 sslErrorLog("SSLProcessCertificateRequest: length decode error 2\n");
265 return errSSLProtocol
;
267 for (i
= 0; i
< typeCount
; i
++)
268 { if (*charPtr
++ == 1)
269 ctx
->x509Requested
= 1;
273 /* FIXME - currently untested */
280 dnListLen
= SSLDecodeInt(charPtr
, 2);
282 if (message
.length
!= 3 + typeCount
+ dnListLen
) {
283 sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n");
284 return errSSLProtocol
;
286 while (dnListLen
> 0)
287 { if (dnListLen
< 2) {
288 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 1\n");
289 return errSSLProtocol
;
291 dnLen
= SSLDecodeInt(charPtr
, 2);
293 if (dnListLen
< 2 + dnLen
) {
294 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 2\n");
295 return errSSLProtocol
;
297 if ((err
= SSLAllocBuffer(dnBuf
, sizeof(DNListElem
), ctx
)) != 0)
299 dn
= (DNListElem
*)dnBuf
.data
;
300 if ((err
= SSLAllocBuffer(dn
->derDN
, dnLen
, ctx
)) != 0)
301 { SSLFreeBuffer(dnBuf
, ctx
);
304 memcpy(dn
->derDN
.data
, charPtr
, dnLen
);
306 dn
->next
= ctx
->acceptableDNList
;
307 ctx
->acceptableDNList
= dn
;
308 dnListLen
-= 2 + dnLen
;
311 assert(charPtr
== message
.data
+ message
.length
);
312 #endif /* untested client-side authentication */
318 SSLEncodeCertificateVerify(SSLRecord
&certVerify
, SSLContext
*ctx
)
321 SSLBuffer hashDataBuf
, shaMsgState
, md5MsgState
;
324 const CSSM_KEY
*cssmKey
;
326 certVerify
.contents
.data
= 0;
327 hashDataBuf
.data
= hashData
;
328 hashDataBuf
.length
= 36;
330 if ((err
= CloneHashState(SSLHashSHA1
, ctx
->shaState
, shaMsgState
, ctx
)) != 0)
332 if ((err
= CloneHashState(SSLHashMD5
, ctx
->md5State
, md5MsgState
, ctx
)) != 0)
334 assert(ctx
->sslTslCalls
!= NULL
);
335 if ((err
= ctx
->sslTslCalls
->computeCertVfyMac(ctx
, hashDataBuf
,
336 shaMsgState
, md5MsgState
)) != 0)
339 assert(ctx
->signingPrivKeyRef
!= NULL
);
340 err
= SecKeyGetCSSMKey(ctx
->signingPrivKeyRef
, &cssmKey
);
342 sslErrorLog("SSLEncodeCertificateVerify: SecKeyGetCSSMKey err %d\n", (int)err
);
345 len
= sslKeyLengthInBytes(cssmKey
);
347 certVerify
.contentType
= SSL_RecordTypeHandshake
;
348 assert((ctx
->negProtocolVersion
== SSL_Version_3_0
) ||
349 (ctx
->negProtocolVersion
== TLS_Version_1_0
));
350 certVerify
.protocolVersion
= ctx
->negProtocolVersion
;
351 if ((err
= SSLAllocBuffer(certVerify
.contents
, len
+ 6, ctx
)) != 0)
354 certVerify
.contents
.data
[0] = SSL_HdskCertVerify
;
355 SSLEncodeInt(certVerify
.contents
.data
+1, len
+2, 3);
356 SSLEncodeInt(certVerify
.contents
.data
+4, len
, 2);
358 err
= sslRawSign(ctx
,
359 ctx
->signingPrivKeyRef
,
360 hashData
, // data to sign
361 36, // MD5 size + SHA1 size
362 certVerify
.contents
.data
+6, // signature destination
363 len
, // we mallocd len+6
369 assert(outputLen
== len
);
374 SSLFreeBuffer(shaMsgState
, ctx
);
375 SSLFreeBuffer(md5MsgState
, ctx
);
381 SSLProcessCertificateVerify(SSLBuffer message
, SSLContext
*ctx
)
385 SSLBuffer hashDataBuf
, shaMsgState
, md5MsgState
;
386 unsigned int publicModulusLen
;
388 shaMsgState
.data
= 0;
389 md5MsgState
.data
= 0;
391 if (message
.length
< 2) {
392 sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
393 return errSSLProtocol
;
396 signatureLen
= (UInt16
)SSLDecodeInt(message
.data
, 2);
397 if (message
.length
!= (unsigned)(2 + signatureLen
)) {
398 sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n");
399 return errSSLProtocol
;
402 assert(ctx
->peerPubKey
!= NULL
);
403 publicModulusLen
= sslKeyLengthInBytes(ctx
->peerPubKey
);
405 if (signatureLen
!= publicModulusLen
) {
406 sslErrorLog("SSLProcessCertificateVerify: sig len error 2\n");
407 return errSSLProtocol
;
409 hashDataBuf
.data
= hashData
;
410 hashDataBuf
.length
= 36;
412 if ((err
= CloneHashState(SSLHashSHA1
, ctx
->shaState
, shaMsgState
, ctx
)) != 0)
414 if ((err
= CloneHashState(SSLHashMD5
, ctx
->md5State
, md5MsgState
, ctx
)) != 0)
416 assert(ctx
->sslTslCalls
!= NULL
);
417 if ((err
= ctx
->sslTslCalls
->computeCertVfyMac(ctx
, hashDataBuf
,
418 shaMsgState
, md5MsgState
)) != 0)
422 * The CSP does the decrypt & compare for us in one shot
424 err
= sslRawVerify(ctx
,
426 ctx
->peerPubKeyCsp
, // FIXME - maybe we just use cspHand?
427 hashData
, // data to verify
429 message
.data
+ 2, // signature
432 SSLFatalSessionAlert(SSL_AlertDecryptError
, ctx
);
438 SSLFreeBuffer(shaMsgState
, ctx
);
439 SSLFreeBuffer(md5MsgState
, ctx
);