]> git.saurik.com Git - apple/security.git/blob - SecureTransport/sslCert.cpp
Security-54.1.3.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 return errSSLXCertChainInvalid;
156 }
157 }
158 if((err = sslVerifyCertChain(ctx, *ctx->peerCert)) != 0)
159 return err;
160
161 /* peer's certificate is the last one in the chain */
162 cert = ctx->peerCert;
163 while (cert->next != 0)
164 cert = cert->next;
165 /* Convert its public key to CDSA format */
166 if ((err = sslPubKeyFromCert(ctx,
167 cert->derCert,
168 &ctx->peerPubKey,
169 &ctx->peerPubKeyCsp)) != 0)
170 return err;
171
172 return noErr;
173 }
174
175 OSStatus
176 SSLEncodeCertificateRequest(SSLRecord &request, SSLContext *ctx)
177 {
178 OSStatus err;
179 UInt32 dnListLen, msgLen;
180 UInt8 *charPtr;
181 DNListElem *dn;
182
183 assert(ctx->protocolSide == SSL_ServerSide);
184 dnListLen = 0;
185 dn = ctx->acceptableDNList;
186 while (dn)
187 { dnListLen += 2 + dn->derDN.length;
188 dn = dn->next;
189 }
190 msgLen = 1 + 1 + 2 + dnListLen;
191
192 request.contentType = SSL_RecordTypeHandshake;
193 assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
194 (ctx->negProtocolVersion == TLS_Version_1_0));
195 request.protocolVersion = ctx->negProtocolVersion;
196 if ((err = SSLAllocBuffer(request.contents, msgLen + 4, ctx)) != 0)
197 return err;
198
199 charPtr = request.contents.data;
200 *charPtr++ = SSL_HdskCertRequest;
201 charPtr = SSLEncodeInt(charPtr, msgLen, 3);
202
203 *charPtr++ = 1; /* one cert type */
204 *charPtr++ = 1; /* RSA-sign type */
205 charPtr = SSLEncodeInt(charPtr, dnListLen, 2);
206 dn = ctx->acceptableDNList;
207 while (dn)
208 { charPtr = SSLEncodeInt(charPtr, dn->derDN.length, 2);
209 memcpy(charPtr, dn->derDN.data, dn->derDN.length);
210 charPtr += dn->derDN.length;
211 dn = dn->next;
212 }
213
214 assert(charPtr == request.contents.data + request.contents.length);
215 return noErr;
216 }
217
218 OSStatus
219 SSLProcessCertificateRequest(SSLBuffer message, SSLContext *ctx)
220 {
221 unsigned i;
222 unsigned typeCount;
223 UInt8 *charPtr;
224
225 /*
226 * Cert request only happens in during client authentication, which
227 * we don't do. We will however take this handshake msg and do
228 * nothing with the enclosed DNList. We'll send a client cert
229 * if we have one but we don't do any DNList compare.
230 */
231 if (message.length < 3) {
232 sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n");
233 return errSSLProtocol;
234 }
235 charPtr = message.data;
236 typeCount = *charPtr++;
237 if (typeCount < 1 || message.length < 3 + typeCount) {
238 sslErrorLog("SSLProcessCertificateRequest: length decode error 2\n");
239 return errSSLProtocol;
240 }
241 for (i = 0; i < typeCount; i++)
242 { if (*charPtr++ == 1)
243 ctx->x509Requested = 1;
244 }
245
246 #if 0
247 /* FIXME - currently untested */
248 unsigned dnListLen;
249 unsigned dnLen;
250 SSLBuffer dnBuf;
251 DNListElem *dn;
252 OSStatus err;
253
254 dnListLen = SSLDecodeInt(charPtr, 2);
255 charPtr += 2;
256 if (message.length != 3 + typeCount + dnListLen) {
257 sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n");
258 return errSSLProtocol;
259 }
260 while (dnListLen > 0)
261 { if (dnListLen < 2) {
262 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 1\n");
263 return errSSLProtocol;
264 }
265 dnLen = SSLDecodeInt(charPtr, 2);
266 charPtr += 2;
267 if (dnListLen < 2 + dnLen) {
268 sslErrorLog("SSLProcessCertificateRequest: dnListLen error 2\n");
269 return errSSLProtocol;
270 }
271 if ((err = SSLAllocBuffer(dnBuf, sizeof(DNListElem), ctx)) != 0)
272 return err;
273 dn = (DNListElem*)dnBuf.data;
274 if ((err = SSLAllocBuffer(dn->derDN, dnLen, ctx)) != 0)
275 { SSLFreeBuffer(dnBuf, ctx);
276 return err;
277 }
278 memcpy(dn->derDN.data, charPtr, dnLen);
279 charPtr += dnLen;
280 dn->next = ctx->acceptableDNList;
281 ctx->acceptableDNList = dn;
282 dnListLen -= 2 + dnLen;
283 }
284
285 assert(charPtr == message.data + message.length);
286 #endif /* untested client-side authentication */
287
288 return noErr;
289 }
290
291 OSStatus
292 SSLEncodeCertificateVerify(SSLRecord &certVerify, SSLContext *ctx)
293 { OSStatus err;
294 UInt8 hashData[36];
295 SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
296 UInt32 len;
297 UInt32 outputLen;
298
299 certVerify.contents.data = 0;
300 hashDataBuf.data = hashData;
301 hashDataBuf.length = 36;
302
303 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
304 goto fail;
305 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
306 goto fail;
307 assert(ctx->sslTslCalls != NULL);
308 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
309 shaMsgState, md5MsgState)) != 0)
310 goto fail;
311
312 assert(ctx->signingPrivKey != NULL);
313 len = sslKeyLengthInBytes(ctx->signingPrivKey);
314
315 certVerify.contentType = SSL_RecordTypeHandshake;
316 assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
317 (ctx->negProtocolVersion == TLS_Version_1_0));
318 certVerify.protocolVersion = ctx->negProtocolVersion;
319 if ((err = SSLAllocBuffer(certVerify.contents, len + 6, ctx)) != 0)
320 goto fail;
321
322 certVerify.contents.data[0] = SSL_HdskCertVerify;
323 SSLEncodeInt(certVerify.contents.data+1, len+2, 3);
324 SSLEncodeInt(certVerify.contents.data+4, len, 2);
325
326 err = sslRsaRawSign(ctx,
327 ctx->signingPrivKey,
328 ctx->signingKeyCsp,
329 hashData, // data to sign
330 36, // MD5 size + SHA1 size
331 certVerify.contents.data+6, // signature destination
332 len, // we mallocd len+6
333 &outputLen);
334 if(err) {
335 goto fail;
336 }
337
338 assert(outputLen == len);
339
340 err = noErr;
341
342 fail:
343 SSLFreeBuffer(shaMsgState, ctx);
344 SSLFreeBuffer(md5MsgState, ctx);
345
346 return err;
347 }
348
349 OSStatus
350 SSLProcessCertificateVerify(SSLBuffer message, SSLContext *ctx)
351 { OSStatus err;
352 UInt8 hashData[36];
353 UInt16 signatureLen;
354 SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
355 unsigned int publicModulusLen;
356
357 shaMsgState.data = 0;
358 md5MsgState.data = 0;
359
360 if (message.length < 2) {
361 sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
362 return errSSLProtocol;
363 }
364
365 signatureLen = (UInt16)SSLDecodeInt(message.data, 2);
366 if (message.length != (unsigned)(2 + signatureLen)) {
367 sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n");
368 return errSSLProtocol;
369 }
370
371 assert(ctx->peerPubKey != NULL);
372 publicModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
373
374 if (signatureLen != publicModulusLen) {
375 sslErrorLog("SSLProcessCertificateVerify: sig len error 2\n");
376 return errSSLProtocol;
377 }
378 hashDataBuf.data = hashData;
379 hashDataBuf.length = 36;
380
381 if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
382 goto fail;
383 if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
384 goto fail;
385 assert(ctx->sslTslCalls != NULL);
386 if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
387 shaMsgState, md5MsgState)) != 0)
388 goto fail;
389
390 /*
391 * The CSP does the decrypt & compare for us in one shot
392 */
393 err = sslRsaRawVerify(ctx,
394 ctx->peerPubKey,
395 ctx->peerPubKeyCsp, // FIXME - maybe we just use cspHand?
396 hashData, // data to verify
397 36,
398 message.data + 2, // signature
399 signatureLen);
400 if(err) {
401 goto fail;
402 }
403 err = noErr;
404
405 fail:
406 SSLFreeBuffer(shaMsgState, ctx);
407 SSLFreeBuffer(md5MsgState, ctx);
408
409 return err;
410 }