]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslCert.cpp
c9277f2ebb68bb8a9eb258565e4f4ec17bfc733d
[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
325 certVerify.contents.data = 0;
326 hashDataBuf.data = hashData;
327 hashDataBuf.length = 36;
328
329 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
330 goto fail;
331 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
332 goto fail;
333 assert(ctx->sslTslCalls != NULL);
334 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
335 shaMsgState, md5MsgState)) != 0)
336 goto fail;
337
338 assert(ctx->signingPrivKey != NULL);
339 len = sslKeyLengthInBytes(ctx->signingPrivKey);
340
341 certVerify.contentType = SSL_RecordTypeHandshake;
342 assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
343 (ctx->negProtocolVersion == TLS_Version_1_0));
344 certVerify.protocolVersion = ctx->negProtocolVersion;
345 if ((err = SSLAllocBuffer(certVerify.contents, len + 6, ctx)) != 0)
346 goto fail;
347
348 certVerify.contents.data[0] = SSL_HdskCertVerify;
349 SSLEncodeInt(certVerify.contents.data+1, len+2, 3);
350 SSLEncodeInt(certVerify.contents.data+4, len, 2);
351
352 err = sslRawSign(ctx,
353 ctx->signingPrivKey,
354 ctx->signingKeyCsp,
355 hashData, // data to sign
356 36, // MD5 size + SHA1 size
357 certVerify.contents.data+6, // signature destination
358 len, // we mallocd len+6
359 &outputLen);
360 if(err) {
361 goto fail;
362 }
363
364 assert(outputLen == len);
365
366 err = noErr;
367
368 fail:
369 SSLFreeBuffer(shaMsgState, ctx);
370 SSLFreeBuffer(md5MsgState, ctx);
371
372 return err;
373 }
374
375 OSStatus
376 SSLProcessCertificateVerify(SSLBuffer message, SSLContext *ctx)
377 { OSStatus err;
378 UInt8 hashData[36];
379 UInt16 signatureLen;
380 SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
381 unsigned int publicModulusLen;
382
383 shaMsgState.data = 0;
384 md5MsgState.data = 0;
385
386 if (message.length < 2) {
387 sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
388 return errSSLProtocol;
389 }
390
391 signatureLen = (UInt16)SSLDecodeInt(message.data, 2);
392 if (message.length != (unsigned)(2 + signatureLen)) {
393 sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n");
394 return errSSLProtocol;
395 }
396
397 assert(ctx->peerPubKey != NULL);
398 publicModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
399
400 if (signatureLen != publicModulusLen) {
401 sslErrorLog("SSLProcessCertificateVerify: sig len error 2\n");
402 return errSSLProtocol;
403 }
404 hashDataBuf.data = hashData;
405 hashDataBuf.length = 36;
406
407 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
408 goto fail;
409 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
410 goto fail;
411 assert(ctx->sslTslCalls != NULL);
412 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
413 shaMsgState, md5MsgState)) != 0)
414 goto fail;
415
416 /*
417 * The CSP does the decrypt & compare for us in one shot
418 */
419 err = sslRawVerify(ctx,
420 ctx->peerPubKey,
421 ctx->peerPubKeyCsp, // FIXME - maybe we just use cspHand?
422 hashData, // data to verify
423 36,
424 message.data + 2, // signature
425 signatureLen);
426 if(err) {
427 SSLFatalSessionAlert(SSL_AlertDecryptError, ctx);
428 goto fail;
429 }
430 err = noErr;
431
432 fail:
433 SSLFreeBuffer(shaMsgState, ctx);
434 SSLFreeBuffer(md5MsgState, ctx);
435
436 return err;
437 }