]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslCert.cpp
Security-177.tar.gz
[apple/security.git] / SecureTransport / sslCert.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
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
8 * using this file.
9 *
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.
16 */
17
18
19 /*
20 File: sslCert.cpp
21
22 Contains: certificate request/verify messages
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29 #include "sslContext.h"
30 #include "sslHandshake.h"
31 #include "sslMemory.h"
32 #include "sslAlertMessage.h"
33 #include "sslDebug.h"
34 #include "sslUtils.h"
35 #include "sslDigests.h"
36 #include "appleCdsa.h"
37
38 #include <string.h>
39 #include <assert.h>
40
41 OSStatus
42 SSLEncodeCertificate(SSLRecord &certificate, SSLContext *ctx)
43 { OSStatus err;
44 UInt32 totalLength;
45 int i, j, certCount;
46 UInt8 *charPtr;
47 SSLCertificate *cert;
48
49 /*
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.
53 *
54 * Note this can be called with localCert==0 for client seide in TLS1;
55 * in that case we send an empty cert msg.
56 */
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));
61 totalLength = 0;
62 certCount = 0;
63 while (cert)
64 { totalLength += 3 + cert->derCert.length; /* 3 for encoded length field */
65 ++certCount;
66 cert = cert->next;
67 }
68
69 certificate.contentType = SSL_RecordTypeHandshake;
70 certificate.protocolVersion = ctx->negProtocolVersion;
71 if ((err = SSLAllocBuffer(certificate.contents, totalLength + 7, ctx)) != 0)
72 return err;
73
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 */
78
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)
84 cert = cert->next;
85 charPtr = SSLEncodeInt(charPtr, cert->derCert.length, 3);
86 memcpy(charPtr, cert->derCert.data, cert->derCert.length);
87 charPtr += cert->derCert.length;
88 }
89
90 assert(charPtr == certificate.contents.data + certificate.contents.length);
91
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). */
97 ctx->certSent = 1;
98 assert(ctx->clientCertState == kSSLClientCertRequested);
99 assert(ctx->certRequested);
100 ctx->clientCertState = kSSLClientCertSent;
101 }
102 return noErr;
103 }
104
105 OSStatus
106 SSLProcessCertificate(SSLBuffer message, SSLContext *ctx)
107 { OSStatus err;
108 UInt32 listLen, certLen;
109 UInt8 *p;
110 SSLCertificate *cert;
111
112 p = message.data;
113 listLen = SSLDecodeInt(p,3);
114 p += 3;
115 if (listLen + 3 != message.length) {
116 sslErrorLog("SSLProcessCertificate: length decode error 1\n");
117 return errSSLProtocol;
118 }
119
120 while (listLen > 0)
121 { certLen = SSLDecodeInt(p,3);
122 p += 3;
123 if (listLen < certLen + 3) {
124 sslErrorLog("SSLProcessCertificate: length decode error 2\n");
125 return errSSLProtocol;
126 }
127 cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
128 if(cert == NULL) {
129 return memFullErr;
130 }
131 if ((err = SSLAllocBuffer(cert->derCert, certLen, ctx)) != 0)
132 { sslFree(cert);
133 return err;
134 }
135 memcpy(cert->derCert.data, p, certLen);
136 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;
141 }
142 assert(p == message.data + message.length && listLen == 0);
143
144 if (ctx->peerCert == 0) {
145 /* this *might* be OK... */
146 if((ctx->protocolSide == SSL_ServerSide) &&
147 (ctx->clientAuth != kAlwaysAuthenticate)) {
148 /*
149 * we tried to authenticate, client doesn't have a cert, and
150 * app doesn't require it. OK.
151 */
152 return noErr;
153 }
154 else {
155 AlertDescription desc;
156 if(ctx->negProtocolVersion == SSL_Version_3_0) {
157 /* this one's for SSL3 only */
158 desc = SSL_AlertBadCert;
159 }
160 else {
161 desc = SSL_AlertCertUnknown;
162 }
163 SSLFatalSessionAlert(desc, ctx);
164 return errSSLXCertChainInvalid;
165 }
166 }
167 if((err = sslVerifyCertChain(ctx, *ctx->peerCert)) != 0) {
168 AlertDescription desc;
169 switch(err) {
170 case errSSLUnknownRootCert:
171 case errSSLNoRootCert:
172 desc = SSL_AlertUnknownCA;
173 break;
174 case errSSLCertExpired:
175 case errSSLCertNotYetValid:
176 desc = SSL_AlertCertExpired;
177 break;
178 case errSSLXCertChainInvalid:
179 default:
180 desc = SSL_AlertCertUnknown;
181 break;
182 }
183 SSLFatalSessionAlert(desc, ctx);
184 return err;
185 }
186
187 /* peer's certificate is the last one in the chain */
188 cert = ctx->peerCert;
189 while (cert->next != 0)
190 cert = cert->next;
191 /* Convert its public key to CDSA format */
192 if ((err = sslPubKeyFromCert(ctx,
193 cert->derCert,
194 &ctx->peerPubKey,
195 &ctx->peerPubKeyCsp)) != 0)
196 return err;
197
198 return noErr;
199 }
200
201 OSStatus
202 SSLEncodeCertificateRequest(SSLRecord &request, SSLContext *ctx)
203 {
204 OSStatus err;
205 UInt32 dnListLen, msgLen;
206 UInt8 *charPtr;
207 DNListElem *dn;
208
209 assert(ctx->protocolSide == SSL_ServerSide);
210 dnListLen = 0;
211 dn = ctx->acceptableDNList;
212 while (dn)
213 { dnListLen += 2 + dn->derDN.length;
214 dn = dn->next;
215 }
216 msgLen = 1 + 1 + 2 + dnListLen;
217
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)
223 return err;
224
225 charPtr = request.contents.data;
226 *charPtr++ = SSL_HdskCertRequest;
227 charPtr = SSLEncodeInt(charPtr, msgLen, 3);
228
229 *charPtr++ = 1; /* one cert type */
230 *charPtr++ = 1; /* RSA-sign type */
231 charPtr = SSLEncodeInt(charPtr, dnListLen, 2);
232 dn = ctx->acceptableDNList;
233 while (dn)
234 { charPtr = SSLEncodeInt(charPtr, dn->derDN.length, 2);
235 memcpy(charPtr, dn->derDN.data, dn->derDN.length);
236 charPtr += dn->derDN.length;
237 dn = dn->next;
238 }
239
240 assert(charPtr == request.contents.data + request.contents.length);
241 return noErr;
242 }
243
244 OSStatus
245 SSLProcessCertificateRequest(SSLBuffer message, SSLContext *ctx)
246 {
247 unsigned i;
248 unsigned typeCount;
249 UInt8 *charPtr;
250
251 /*
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.
256 */
257 if (message.length < 3) {
258 sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n");
259 return errSSLProtocol;
260 }
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;
266 }
267 for (i = 0; i < typeCount; i++)
268 { if (*charPtr++ == 1)
269 ctx->x509Requested = 1;
270 }
271
272 #if 0
273 /* FIXME - currently untested */
274 unsigned dnListLen;
275 unsigned dnLen;
276 SSLBuffer dnBuf;
277 DNListElem *dn;
278 OSStatus err;
279
280 dnListLen = SSLDecodeInt(charPtr, 2);
281 charPtr += 2;
282 if (message.length != 3 + typeCount + dnListLen) {
283 sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n");
284 return errSSLProtocol;
285 }
286 while (dnListLen > 0)
287 { if (dnListLen < 2) {
288 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 1\n");
289 return errSSLProtocol;
290 }
291 dnLen = SSLDecodeInt(charPtr, 2);
292 charPtr += 2;
293 if (dnListLen < 2 + dnLen) {
294 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 2\n");
295 return errSSLProtocol;
296 }
297 if ((err = SSLAllocBuffer(dnBuf, sizeof(DNListElem), ctx)) != 0)
298 return err;
299 dn = (DNListElem*)dnBuf.data;
300 if ((err = SSLAllocBuffer(dn->derDN, dnLen, ctx)) != 0)
301 { SSLFreeBuffer(dnBuf, ctx);
302 return err;
303 }
304 memcpy(dn->derDN.data, charPtr, dnLen);
305 charPtr += dnLen;
306 dn->next = ctx->acceptableDNList;
307 ctx->acceptableDNList = dn;
308 dnListLen -= 2 + dnLen;
309 }
310
311 assert(charPtr == message.data + message.length);
312 #endif /* untested client-side authentication */
313
314 return noErr;
315 }
316
317 OSStatus
318 SSLEncodeCertificateVerify(SSLRecord &certVerify, SSLContext *ctx)
319 { OSStatus err;
320 UInt8 hashData[36];
321 SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
322 UInt32 len;
323 UInt32 outputLen;
324 const CSSM_KEY *cssmKey;
325
326 certVerify.contents.data = 0;
327 hashDataBuf.data = hashData;
328 hashDataBuf.length = 36;
329
330 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
331 goto fail;
332 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
333 goto fail;
334 assert(ctx->sslTslCalls != NULL);
335 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
336 shaMsgState, md5MsgState)) != 0)
337 goto fail;
338
339 assert(ctx->signingPrivKeyRef != NULL);
340 err = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
341 if(err) {
342 sslErrorLog("SSLEncodeCertificateVerify: SecKeyGetCSSMKey err %d\n", (int)err);
343 return err;
344 }
345 len = sslKeyLengthInBytes(cssmKey);
346
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)
352 goto fail;
353
354 certVerify.contents.data[0] = SSL_HdskCertVerify;
355 SSLEncodeInt(certVerify.contents.data+1, len+2, 3);
356 SSLEncodeInt(certVerify.contents.data+4, len, 2);
357
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
364 &outputLen);
365 if(err) {
366 goto fail;
367 }
368
369 assert(outputLen == len);
370
371 err = noErr;
372
373 fail:
374 SSLFreeBuffer(shaMsgState, ctx);
375 SSLFreeBuffer(md5MsgState, ctx);
376
377 return err;
378 }
379
380 OSStatus
381 SSLProcessCertificateVerify(SSLBuffer message, SSLContext *ctx)
382 { OSStatus err;
383 UInt8 hashData[36];
384 UInt16 signatureLen;
385 SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
386 unsigned int publicModulusLen;
387
388 shaMsgState.data = 0;
389 md5MsgState.data = 0;
390
391 if (message.length < 2) {
392 sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
393 return errSSLProtocol;
394 }
395
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;
400 }
401
402 assert(ctx->peerPubKey != NULL);
403 publicModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
404
405 if (signatureLen != publicModulusLen) {
406 sslErrorLog("SSLProcessCertificateVerify: sig len error 2\n");
407 return errSSLProtocol;
408 }
409 hashDataBuf.data = hashData;
410 hashDataBuf.length = 36;
411
412 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
413 goto fail;
414 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
415 goto fail;
416 assert(ctx->sslTslCalls != NULL);
417 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
418 shaMsgState, md5MsgState)) != 0)
419 goto fail;
420
421 /*
422 * The CSP does the decrypt & compare for us in one shot
423 */
424 err = sslRawVerify(ctx,
425 ctx->peerPubKey,
426 ctx->peerPubKeyCsp, // FIXME - maybe we just use cspHand?
427 hashData, // data to verify
428 36,
429 message.data + 2, // signature
430 signatureLen);
431 if(err) {
432 SSLFatalSessionAlert(SSL_AlertDecryptError, ctx);
433 goto fail;
434 }
435 err = noErr;
436
437 fail:
438 SSLFreeBuffer(shaMsgState, ctx);
439 SSLFreeBuffer(md5MsgState, ctx);
440
441 return err;
442 }