+++ /dev/null
-/*
- * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-/*
- File: sslCert.cpp
-
- Contains: certificate request/verify messages
-
- Written by: Doug Mitchell
-
- Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
-
-*/
-#include "sslContext.h"
-#include "sslHandshake.h"
-#include "sslMemory.h"
-#include "sslAlertMessage.h"
-#include "sslDebug.h"
-#include "sslUtils.h"
-#include "sslDigests.h"
-#include "appleCdsa.h"
-
-#include <string.h>
-#include <assert.h>
-
-OSStatus
-SSLEncodeCertificate(SSLRecord &certificate, SSLContext *ctx)
-{ OSStatus err;
- UInt32 totalLength;
- int i, j, certCount;
- UInt8 *charPtr;
- SSLCertificate *cert;
-
- /*
- * TBD: for client side, match Match DER-encoded acceptable DN list
- * (ctx->acceptableDNList) to one of our certs. For now we just send
- * what we have since we don't support multiple certs.
- *
- * Note this can be called with localCert==0 for client seide in TLS1;
- * in that case we send an empty cert msg.
- */
- cert = ctx->localCert;
- assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
- (ctx->negProtocolVersion == TLS_Version_1_0));
- assert((cert != NULL) || (ctx->negProtocolVersion == TLS_Version_1_0));
- totalLength = 0;
- certCount = 0;
- while (cert)
- { totalLength += 3 + cert->derCert.length; /* 3 for encoded length field */
- ++certCount;
- cert = cert->next;
- }
-
- certificate.contentType = SSL_RecordTypeHandshake;
- certificate.protocolVersion = ctx->negProtocolVersion;
- if ((err = SSLAllocBuffer(certificate.contents, totalLength + 7, ctx)) != 0)
- return err;
-
- charPtr = certificate.contents.data;
- *charPtr++ = SSL_HdskCert;
- charPtr = SSLEncodeInt(charPtr, totalLength+3, 3); /* Handshake message length */
- charPtr = SSLEncodeInt(charPtr, totalLength, 3); /* Vector length */
-
- /* Root cert is first in the linked list, but has to go last,
- * so walk list backwards */
- for (i = 0; i < certCount; ++i)
- { cert = ctx->localCert;
- for (j = i+1; j < certCount; ++j)
- cert = cert->next;
- charPtr = SSLEncodeInt(charPtr, cert->derCert.length, 3);
- memcpy(charPtr, cert->derCert.data, cert->derCert.length);
- charPtr += cert->derCert.length;
- }
-
- assert(charPtr == certificate.contents.data + certificate.contents.length);
-
- if ((ctx->protocolSide == SSL_ClientSide) && (ctx->localCert)) {
- /* this tells us to send a CertificateVerify msg after the
- * client key exchange. We skip the cert vfy if we just
- * sent an empty cert msg (i.e., we were asked for a cert
- * but we don't have one). */
- ctx->certSent = 1;
- assert(ctx->clientCertState == kSSLClientCertRequested);
- assert(ctx->certRequested);
- ctx->clientCertState = kSSLClientCertSent;
- }
- return noErr;
-}
-
-OSStatus
-SSLProcessCertificate(SSLBuffer message, SSLContext *ctx)
-{ OSStatus err;
- UInt32 listLen, certLen;
- UInt8 *p;
- SSLCertificate *cert;
-
- p = message.data;
- listLen = SSLDecodeInt(p,3);
- p += 3;
- if (listLen + 3 != message.length) {
- sslErrorLog("SSLProcessCertificate: length decode error 1\n");
- return errSSLProtocol;
- }
-
- while (listLen > 0)
- { certLen = SSLDecodeInt(p,3);
- p += 3;
- if (listLen < certLen + 3) {
- sslErrorLog("SSLProcessCertificate: length decode error 2\n");
- return errSSLProtocol;
- }
- cert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate));
- if(cert == NULL) {
- return memFullErr;
- }
- if ((err = SSLAllocBuffer(cert->derCert, certLen, ctx)) != 0)
- { sslFree(cert);
- return err;
- }
- memcpy(cert->derCert.data, p, certLen);
- p += certLen;
- cert->next = ctx->peerCert; /* Insert backwards; root cert
- * will be first in linked list */
- ctx->peerCert = cert;
- listLen -= 3+certLen;
- }
- assert(p == message.data + message.length && listLen == 0);
-
- if (ctx->peerCert == 0) {
- /* this *might* be OK... */
- if((ctx->protocolSide == SSL_ServerSide) &&
- (ctx->clientAuth != kAlwaysAuthenticate)) {
- /*
- * we tried to authenticate, client doesn't have a cert, and
- * app doesn't require it. OK.
- */
- return noErr;
- }
- else {
- AlertDescription desc;
- if(ctx->negProtocolVersion == SSL_Version_3_0) {
- /* this one's for SSL3 only */
- desc = SSL_AlertBadCert;
- }
- else {
- desc = SSL_AlertCertUnknown;
- }
- SSLFatalSessionAlert(desc, ctx);
- return errSSLXCertChainInvalid;
- }
- }
- if((err = sslVerifyCertChain(ctx, *ctx->peerCert)) != 0) {
- AlertDescription desc;
- switch(err) {
- case errSSLUnknownRootCert:
- case errSSLNoRootCert:
- desc = SSL_AlertUnknownCA;
- break;
- case errSSLCertExpired:
- case errSSLCertNotYetValid:
- desc = SSL_AlertCertExpired;
- break;
- case errSSLXCertChainInvalid:
- default:
- desc = SSL_AlertCertUnknown;
- break;
- }
- SSLFatalSessionAlert(desc, ctx);
- return err;
- }
-
- /* peer's certificate is the last one in the chain */
- cert = ctx->peerCert;
- while (cert->next != 0)
- cert = cert->next;
- /* Convert its public key to CDSA format */
- if ((err = sslPubKeyFromCert(ctx,
- cert->derCert,
- &ctx->peerPubKey,
- &ctx->peerPubKeyCsp)) != 0)
- return err;
-
- return noErr;
-}
-
-OSStatus
-SSLEncodeCertificateRequest(SSLRecord &request, SSLContext *ctx)
-{
- OSStatus err;
- UInt32 dnListLen, msgLen;
- UInt8 *charPtr;
- DNListElem *dn;
-
- assert(ctx->protocolSide == SSL_ServerSide);
- dnListLen = 0;
- dn = ctx->acceptableDNList;
- while (dn)
- { dnListLen += 2 + dn->derDN.length;
- dn = dn->next;
- }
- msgLen = 1 + 1 + 2 + dnListLen;
-
- request.contentType = SSL_RecordTypeHandshake;
- assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
- (ctx->negProtocolVersion == TLS_Version_1_0));
- request.protocolVersion = ctx->negProtocolVersion;
- if ((err = SSLAllocBuffer(request.contents, msgLen + 4, ctx)) != 0)
- return err;
-
- charPtr = request.contents.data;
- *charPtr++ = SSL_HdskCertRequest;
- charPtr = SSLEncodeInt(charPtr, msgLen, 3);
-
- *charPtr++ = 1; /* one cert type */
- *charPtr++ = 1; /* RSA-sign type */
- charPtr = SSLEncodeInt(charPtr, dnListLen, 2);
- dn = ctx->acceptableDNList;
- while (dn)
- { charPtr = SSLEncodeInt(charPtr, dn->derDN.length, 2);
- memcpy(charPtr, dn->derDN.data, dn->derDN.length);
- charPtr += dn->derDN.length;
- dn = dn->next;
- }
-
- assert(charPtr == request.contents.data + request.contents.length);
- return noErr;
-}
-
-OSStatus
-SSLProcessCertificateRequest(SSLBuffer message, SSLContext *ctx)
-{
- unsigned i;
- unsigned typeCount;
- UInt8 *charPtr;
-
- /*
- * Cert request only happens in during client authentication, which
- * we don't do. We will however take this handshake msg and do
- * nothing with the enclosed DNList. We'll send a client cert
- * if we have one but we don't do any DNList compare.
- */
- if (message.length < 3) {
- sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n");
- return errSSLProtocol;
- }
- charPtr = message.data;
- typeCount = *charPtr++;
- if (typeCount < 1 || message.length < 3 + typeCount) {
- sslErrorLog("SSLProcessCertificateRequest: length decode error 2\n");
- return errSSLProtocol;
- }
- for (i = 0; i < typeCount; i++)
- { if (*charPtr++ == 1)
- ctx->x509Requested = 1;
- }
-
- #if 0
- /* FIXME - currently untested */
- unsigned dnListLen;
- unsigned dnLen;
- SSLBuffer dnBuf;
- DNListElem *dn;
- OSStatus err;
-
- dnListLen = SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- if (message.length != 3 + typeCount + dnListLen) {
- sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n");
- return errSSLProtocol;
- }
- while (dnListLen > 0)
- { if (dnListLen < 2) {
- sslErrorLog("SSLProcessCertificateRequest: dnListLen error 1\n");
- return errSSLProtocol;
- }
- dnLen = SSLDecodeInt(charPtr, 2);
- charPtr += 2;
- if (dnListLen < 2 + dnLen) {
- sslErrorLog("SSLProcessCertificateRequest: dnListLen error 2\n");
- return errSSLProtocol;
- }
- if ((err = SSLAllocBuffer(dnBuf, sizeof(DNListElem), ctx)) != 0)
- return err;
- dn = (DNListElem*)dnBuf.data;
- if ((err = SSLAllocBuffer(dn->derDN, dnLen, ctx)) != 0)
- { SSLFreeBuffer(dnBuf, ctx);
- return err;
- }
- memcpy(dn->derDN.data, charPtr, dnLen);
- charPtr += dnLen;
- dn->next = ctx->acceptableDNList;
- ctx->acceptableDNList = dn;
- dnListLen -= 2 + dnLen;
- }
-
- assert(charPtr == message.data + message.length);
- #endif /* untested client-side authentication */
-
- return noErr;
-}
-
-OSStatus
-SSLEncodeCertificateVerify(SSLRecord &certVerify, SSLContext *ctx)
-{ OSStatus err;
- UInt8 hashData[36];
- SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
- UInt32 len;
- UInt32 outputLen;
- const CSSM_KEY *cssmKey;
-
- certVerify.contents.data = 0;
- hashDataBuf.data = hashData;
- hashDataBuf.length = 36;
-
- if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
- goto fail;
- if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
- goto fail;
- assert(ctx->sslTslCalls != NULL);
- if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
- shaMsgState, md5MsgState)) != 0)
- goto fail;
-
- assert(ctx->signingPrivKeyRef != NULL);
- err = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
- if(err) {
- sslErrorLog("SSLEncodeCertificateVerify: SecKeyGetCSSMKey err %d\n", (int)err);
- return err;
- }
- len = sslKeyLengthInBytes(cssmKey);
-
- certVerify.contentType = SSL_RecordTypeHandshake;
- assert((ctx->negProtocolVersion == SSL_Version_3_0) ||
- (ctx->negProtocolVersion == TLS_Version_1_0));
- certVerify.protocolVersion = ctx->negProtocolVersion;
- if ((err = SSLAllocBuffer(certVerify.contents, len + 6, ctx)) != 0)
- goto fail;
-
- certVerify.contents.data[0] = SSL_HdskCertVerify;
- SSLEncodeInt(certVerify.contents.data+1, len+2, 3);
- SSLEncodeInt(certVerify.contents.data+4, len, 2);
-
- err = sslRawSign(ctx,
- ctx->signingPrivKeyRef,
- hashData, // data to sign
- 36, // MD5 size + SHA1 size
- certVerify.contents.data+6, // signature destination
- len, // we mallocd len+6
- &outputLen);
- if(err) {
- goto fail;
- }
-
- assert(outputLen == len);
-
- err = noErr;
-
-fail:
- SSLFreeBuffer(shaMsgState, ctx);
- SSLFreeBuffer(md5MsgState, ctx);
-
- return err;
-}
-
-OSStatus
-SSLProcessCertificateVerify(SSLBuffer message, SSLContext *ctx)
-{ OSStatus err;
- UInt8 hashData[36];
- UInt16 signatureLen;
- SSLBuffer hashDataBuf, shaMsgState, md5MsgState;
- unsigned int publicModulusLen;
-
- shaMsgState.data = 0;
- md5MsgState.data = 0;
-
- if (message.length < 2) {
- sslErrorLog("SSLProcessCertificateVerify: msg len error\n");
- return errSSLProtocol;
- }
-
- signatureLen = (UInt16)SSLDecodeInt(message.data, 2);
- if (message.length != (unsigned)(2 + signatureLen)) {
- sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n");
- return errSSLProtocol;
- }
-
- assert(ctx->peerPubKey != NULL);
- publicModulusLen = sslKeyLengthInBytes(ctx->peerPubKey);
-
- if (signatureLen != publicModulusLen) {
- sslErrorLog("SSLProcessCertificateVerify: sig len error 2\n");
- return errSSLProtocol;
- }
- hashDataBuf.data = hashData;
- hashDataBuf.length = 36;
-
- if ((err = CloneHashState(SSLHashSHA1, ctx->shaState, shaMsgState, ctx)) != 0)
- goto fail;
- if ((err = CloneHashState(SSLHashMD5, ctx->md5State, md5MsgState, ctx)) != 0)
- goto fail;
- assert(ctx->sslTslCalls != NULL);
- if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, hashDataBuf,
- shaMsgState, md5MsgState)) != 0)
- goto fail;
-
- /*
- * The CSP does the decrypt & compare for us in one shot
- */
- err = sslRawVerify(ctx,
- ctx->peerPubKey,
- ctx->peerPubKeyCsp, // FIXME - maybe we just use cspHand?
- hashData, // data to verify
- 36,
- message.data + 2, // signature
- signatureLen);
- if(err) {
- SSLFatalSessionAlert(SSL_AlertDecryptError, ctx);
- goto fail;
- }
- err = noErr;
-
-fail:
- SSLFreeBuffer(shaMsgState, ctx);
- SSLFreeBuffer(md5MsgState, ctx);
-
- return err;
-}