/* * 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: sslHandshake.cpp Contains: SSL 3.0 handshake state machine. 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 "sslSession.h" #include "sslUtils.h" #include "sslDebug.h" #include "appleCdsa.h" #include "sslDigests.h" #include #include #define REQUEST_CERT_CORRECT 0 static OSStatus SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx); OSStatus SSLProcessHandshakeRecord(SSLRecord rec, SSLContext *ctx) { OSStatus err; sint32 remaining; UInt8 *p; SSLHandshakeMsg message; SSLBuffer messageData; if (ctx->fragmentedMessageCache.data != 0) { if ((err = SSLReallocBuffer(ctx->fragmentedMessageCache, ctx->fragmentedMessageCache.length + rec.contents.length, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } memcpy(ctx->fragmentedMessageCache.data + ctx->fragmentedMessageCache.length, rec.contents.data, rec.contents.length); remaining = ctx->fragmentedMessageCache.length; p = ctx->fragmentedMessageCache.data; } else { remaining = rec.contents.length; p = rec.contents.data; } while (remaining > 0) { if (remaining < 4) break; /* we must have at least a header */ messageData.data = p; message.type = (SSLHandshakeType)*p++; message.contents.length = SSLDecodeInt(p, 3); if (((int)(message.contents.length + 4)) > remaining) break; p += 3; message.contents.data = p; p += message.contents.length; messageData.length = 4 + message.contents.length; assert(p == messageData.data + messageData.length); /* message fragmentation */ remaining -= messageData.length; if ((err = SSLProcessHandshakeMessage(message, ctx)) != 0) return err; if (message.type != SSL_HdskHelloRequest) { if ((err = SSLHashSHA1.update(ctx->shaState, messageData)) != 0 || (err = SSLHashMD5.update(ctx->md5State, messageData)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } if ((err = SSLAdvanceHandshake(message.type, ctx)) != 0) return err; } if (remaining > 0) /* Fragmented handshake message */ { /* If there isn't a cache, allocate one */ if (ctx->fragmentedMessageCache.data == 0) { if ((err = SSLAllocBuffer(ctx->fragmentedMessageCache, remaining, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } if (p != ctx->fragmentedMessageCache.data) { memcpy(ctx->fragmentedMessageCache.data, p, remaining); ctx->fragmentedMessageCache.length = remaining; } } else if (ctx->fragmentedMessageCache.data != 0) { if ((err = SSLFreeBuffer(ctx->fragmentedMessageCache, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } return noErr; } static OSStatus SSLProcessHandshakeMessage(SSLHandshakeMsg message, SSLContext *ctx) { OSStatus err; err = noErr; SSLLogHdskMsg(message.type, 0); switch (message.type) { case SSL_HdskHelloRequest: if (ctx->protocolSide != SSL_ClientSide) goto wrongMessage; if (message.contents.length > 0) err = errSSLProtocol; break; case SSL_HdskClientHello: if (ctx->state != SSL_HdskStateServerUninit) goto wrongMessage; err = SSLProcessClientHello(message.contents, ctx); break; case SSL_HdskServerHello: if (ctx->state != SSL_HdskStateServerHello && ctx->state != SSL_HdskStateServerHelloUnknownVersion) goto wrongMessage; err = SSLProcessServerHello(message.contents, ctx); break; case SSL_HdskCert: if (ctx->state != SSL_HdskStateCert && ctx->state != SSL_HdskStateClientCert) goto wrongMessage; err = SSLProcessCertificate(message.contents, ctx); if(ctx->protocolSide == SSL_ServerSide) { if(err) { /* * Error could be from no cert (when we require one) * or invalid cert */ if(ctx->peerCert != NULL) { ctx->clientCertState = kSSLClientCertRejected; } } else if(ctx->peerCert != NULL) { /* * This still might change if cert verify msg * fails. Note we avoid going to state * if we get en empty cert message which is * otherwise valid. */ ctx->clientCertState = kSSLClientCertSent; } } break; case SSL_HdskCertRequest: if (((ctx->state != SSL_HdskStateHelloDone) && (ctx->state != SSL_HdskStateKeyExchange)) || ctx->certRequested) goto wrongMessage; err = SSLProcessCertificateRequest(message.contents, ctx); break; case SSL_HdskServerKeyExchange: /* * Since this message is optional, and completely at the * server's discretion, we need to be able to handle this * in one of two states... */ switch(ctx->state) { case SSL_HdskStateKeyExchange: /* explicitly waiting for this */ case SSL_HdskStateHelloDone: break; default: goto wrongMessage; } err = SSLProcessServerKeyExchange(message.contents, ctx); break; case SSL_HdskServerHelloDone: if (ctx->state != SSL_HdskStateHelloDone) goto wrongMessage; err = SSLProcessServerHelloDone(message.contents, ctx); break; case SSL_HdskCertVerify: if (ctx->state != SSL_HdskStateClientCertVerify) goto wrongMessage; err = SSLProcessCertificateVerify(message.contents, ctx); assert(ctx->protocolSide == SSL_ServerSide); if(err) { ctx->clientCertState = kSSLClientCertRejected; } break; case SSL_HdskClientKeyExchange: if (ctx->state != SSL_HdskStateClientKeyExchange) goto wrongMessage; err = SSLProcessKeyExchange(message.contents, ctx); break; case SSL_HdskFinished: if (ctx->state != SSL_HdskStateFinished) goto wrongMessage; err = SSLProcessFinished(message.contents, ctx); break; default: goto wrongMessage; break; } if (err && !ctx->sentFatalAlert) { if (err == errSSLProtocol) SSLFatalSessionAlert(SSL_AlertIllegalParam, ctx); else if (err == errSSLNegotiation) SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); else SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); } return err; wrongMessage: SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx); return errSSLProtocol; } OSStatus SSLAdvanceHandshake(SSLHandshakeType processed, SSLContext *ctx) { OSStatus err; SSLBuffer sessionIdentifier; switch (processed) { case SSL_HdskHelloRequest: /* * Reset the client auth state machine in case this is * a renegotiation. */ ctx->certRequested = 0; ctx->certSent = 0; ctx->certReceived = 0; ctx->x509Requested = 0; ctx->clientCertState = kSSLClientCertNone; if ((err = SSLPrepareAndQueueMessage(SSLEncodeClientHello, ctx)) != 0) return err; SSLChangeHdskState(ctx, SSL_HdskStateServerHello); break; case SSL_HdskClientHello: assert(ctx->protocolSide == SSL_ServerSide); ctx->sessionMatch = 0; if (ctx->sessionID.data != 0) /* If session ID != 0, client is trying to resume */ { if (ctx->resumableSession.data != 0) { SSLProtocolVersion sessionProt; if ((err = SSLRetrieveSessionID(ctx->resumableSession, &sessionIdentifier, ctx)) != 0) return err; if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession, &sessionProt, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } if ((sessionIdentifier.length == ctx->sessionID.length) && (memcmp(sessionIdentifier.data, ctx->sessionID.data, ctx->sessionID.length) == 0) && (sessionProt == ctx->negProtocolVersion)) { /* Everything matches; resume the session */ sslLogResumSessDebug("===RESUMING SSL3 server-side session"); if ((err = SSLInstallSessionFromData(ctx->resumableSession, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } ctx->sessionMatch = 1; if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0) return err; if ((err = SSLInitPendingCiphers(ctx)) != 0 || (err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0) return err; /* Install new cipher spec on write side */ if ((err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } ctx->writeCipher = ctx->writePending; ctx->writeCipher.ready = 0; /* Can't send data until Finished is sent */ memset(&ctx->writePending, 0, sizeof(CipherContext)); /* Zero out old data */ if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0) return err; /* Finished has been sent; enable data t6ransfer on * write channel */ ctx->writeCipher.ready = 1; SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); break; } else { sslLogResumSessDebug( "===FAILED TO RESUME SSL3 server-side session"); } if ((err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0 || (err = SSLDeleteSessionData(ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } if ((err = SSLFreeBuffer(ctx->sessionID, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } /* * If we get here, we're not resuming; generate a new session ID * if we know our peer */ if (ctx->peerID.data != 0) { /* Ignore errors; just treat as uncached session */ assert(ctx->sessionID.data == 0); err = SSLAllocBuffer(ctx->sessionID, SSL_SESSION_ID_LEN, ctx); if (err == 0) { if((err = sslRand(ctx, &ctx->sessionID)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } } if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHello, ctx)) != 0) return err; switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_NULL_auth: #if APPLE_DH case SSL_DH_anon: case SSL_DH_anon_EXPORT: if(ctx->clientAuth == kAlwaysAuthenticate) { /* app requires this; abort */ SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); return errSSLNegotiation; } ctx->tryClientAuth = false; /* DH server side needs work */ break; #endif /* APPLE_DH */ default: /* everything else */ if(ctx->localCert == NULL) { /* no cert but configured for, and negotiated, a * ciphersuite which requires one */ sslErrorLog("SSLAdvanceHandshake: No server key!\n"); return errSSLBadConfiguration; } if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, ctx)) != 0) return err; break; } /* * At this point we decide whether to send a server key exchange * method. For Apple servers, I think we'll ALWAYS do this, because * of key usage restrictions (can't decrypt and sign with the same * private key), but conceptually in this code, we do it if * enabled by the presence of encryptPrivKey. */ { bool doServerKeyExch = false; switch(ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA_EXPORT: #if !SSL_SERVER_KEYEXCH_HACK /* the "proper" way - app decides. */ case SSL_RSA: #endif if(ctx->encryptPrivKeyRef != NULL) { doServerKeyExch = true; } break; case SSL_DH_anon: case SSL_DH_anon_EXPORT: case SSL_DHE_RSA: case SSL_DHE_RSA_EXPORT: case SSL_DHE_DSS: case SSL_DHE_DSS_EXPORT: doServerKeyExch = true; break; default: break; } if(doServerKeyExch) { err = SSLPrepareAndQueueMessage(SSLEncodeServerKeyExchange, ctx); if(err) { return err; } } } if (ctx->tryClientAuth) { if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificateRequest, ctx)) != 0) return err; ctx->certRequested = 1; ctx->clientCertState = kSSLClientCertRequested; } if ((err = SSLPrepareAndQueueMessage(SSLEncodeServerHelloDone, ctx)) != 0) return err; if (ctx->certRequested) { SSLChangeHdskState(ctx, SSL_HdskStateClientCert); } else { SSLChangeHdskState(ctx, SSL_HdskStateClientKeyExchange); } break; case SSL_HdskServerHello: ctx->sessionMatch = 0; if (ctx->resumableSession.data != 0 && ctx->sessionID.data != 0) { SSLProtocolVersion sessionProt; if ((err = SSLRetrieveSessionID(ctx->resumableSession, &sessionIdentifier, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } if ((err = SSLRetrieveSessionProtocolVersion(ctx->resumableSession, &sessionProt, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } if ((sessionIdentifier.length == ctx->sessionID.length) && (memcmp(sessionIdentifier.data, ctx->sessionID.data, ctx->sessionID.length) == 0) && (sessionProt == ctx->negProtocolVersion)) { /* Everything matches; resume the session */ sslLogResumSessDebug("===RESUMING SSL3 client-side session"); if ((err = SSLInstallSessionFromData(ctx->resumableSession, ctx)) != 0 || (err = SSLInitPendingCiphers(ctx)) != 0 || (err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } ctx->sessionMatch = 1; SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); break; } else { sslLogResumSessDebug("===FAILED TO RESUME SSL3 client-side " "session"); } if ((err = SSLFreeBuffer(sessionIdentifier, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } } switch (ctx->selectedCipherSpec->keyExchangeMethod) { /* these require a key exchange message */ case SSL_NULL_auth: case SSL_DH_anon: case SSL_DH_anon_EXPORT: SSLChangeHdskState(ctx, SSL_HdskStateKeyExchange); break; case SSL_RSA: case SSL_DH_DSS: case SSL_DH_DSS_EXPORT: case SSL_DH_RSA: case SSL_DH_RSA_EXPORT: case SSL_RSA_EXPORT: case SSL_DHE_DSS: case SSL_DHE_DSS_EXPORT: case SSL_DHE_RSA: case SSL_DHE_RSA_EXPORT: case SSL_Fortezza: SSLChangeHdskState(ctx, SSL_HdskStateCert); break; default: assert("Unknown key exchange method"); break; } break; case SSL_HdskCert: if (ctx->state == SSL_HdskStateCert) switch (ctx->selectedCipherSpec->keyExchangeMethod) { case SSL_RSA: /* * I really think the two RSA cases should be * handled the same here - the server key exchange is * optional, and is up to the server. * Note this isn't the same as SSL_SERVER_KEYEXCH_HACK; * we're a client here. */ case SSL_RSA_EXPORT: case SSL_DH_DSS: case SSL_DH_DSS_EXPORT: case SSL_DH_RSA: case SSL_DH_RSA_EXPORT: SSLChangeHdskState(ctx, SSL_HdskStateHelloDone); break; case SSL_DHE_DSS: case SSL_DHE_DSS_EXPORT: case SSL_DHE_RSA: case SSL_DHE_RSA_EXPORT: case SSL_Fortezza: SSLChangeHdskState(ctx, SSL_HdskStateKeyExchange); break; default: assert("Unknown or unexpected key exchange method"); break; } else if (ctx->state == SSL_HdskStateClientCert) { SSLChangeHdskState(ctx, SSL_HdskStateClientKeyExchange); if (ctx->peerCert != 0) ctx->certReceived = 1; } break; case SSL_HdskCertRequest: /* state stays in SSL_HdskStateHelloDone; distinction is in * ctx->certRequested */ if (ctx->peerCert == 0) { SSLFatalSessionAlert(SSL_AlertHandshakeFail, ctx); return errSSLProtocol; } ctx->certRequested = 1; ctx->clientCertState = kSSLClientCertRequested; break; case SSL_HdskServerKeyExchange: SSLChangeHdskState(ctx, SSL_HdskStateHelloDone); break; case SSL_HdskServerHelloDone: if (ctx->certRequested) { /* * Server wants a client authentication cert - do * we have one? */ if (ctx->localCert != 0 && ctx->x509Requested) { if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, ctx)) != 0) { return err; } } else { /* response for no cert depends on protocol version */ if(ctx->negProtocolVersion == TLS_Version_1_0) { /* TLS: send empty cert msg */ if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificate, ctx)) != 0) { return err; } } else { /* SSL3: "no cert" alert */ if ((err = SSLSendAlert(SSL_AlertLevelWarning, SSL_AlertNoCert, ctx)) != 0) { return err; } } } /* no cert to send */ } /* server requested a cert */ if ((err = SSLPrepareAndQueueMessage(SSLEncodeKeyExchange, ctx)) != 0) return err; assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 || (err = SSLInitPendingCiphers(ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length); if ((err = SSLFreeBuffer(ctx->preMasterSecret, ctx)) != 0) { return err; } if (ctx->certSent) { if ((err = SSLPrepareAndQueueMessage(SSLEncodeCertificateVerify, ctx)) != 0) { return err; } } if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0) { return err; } /* Install new cipher spec on write side */ if ((err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } ctx->writeCipher = ctx->writePending; /* Can't send data until Finished is sent */ ctx->writeCipher.ready = 0; /* Zero out old data */ memset(&ctx->writePending, 0, sizeof(CipherContext)); ctx->writePending.encrypting = 1; if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0) return err; /* Finished has been sent; enable data transfer on write channel */ ctx->writeCipher.ready = 1; SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); break; case SSL_HdskCertVerify: SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); break; case SSL_HdskClientKeyExchange: assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->generateMasterSecret(ctx)) != 0 || (err = SSLInitPendingCiphers(ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } memset(ctx->preMasterSecret.data, 0, ctx->preMasterSecret.length); if ((err = SSLFreeBuffer(ctx->preMasterSecret, ctx)) != 0) return err; if (ctx->certReceived) { SSLChangeHdskState(ctx, SSL_HdskStateClientCertVerify); } else { SSLChangeHdskState(ctx, SSL_HdskStateChangeCipherSpec); } break; case SSL_HdskFinished: /* Handshake is over; enable data transfer on read channel */ ctx->readCipher.ready = 1; /* If writePending is set, we haven't yet sent a finished message; * send it */ if (ctx->writePending.ready != 0) { if ((err = SSLPrepareAndQueueMessage(SSLEncodeChangeCipherSpec, ctx)) != 0) return err; /* Install new cipher spec on write side */ if ((err = SSLDisposeCipherSuite(&ctx->writeCipher, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } ctx->writeCipher = ctx->writePending; ctx->writeCipher.ready = 0; /* Can't send data until Finished is sent */ memset(&ctx->writePending, 0, sizeof(CipherContext)); /* Zero out old data */ if ((err = SSLPrepareAndQueueMessage(SSLEncodeFinishedMessage, ctx)) != 0) return err; ctx->writeCipher.ready = 1; } if (ctx->protocolSide == SSL_ServerSide) { SSLChangeHdskState(ctx, SSL_HdskStateServerReady); } else { SSLChangeHdskState(ctx, SSL_HdskStateClientReady); } if (ctx->peerID.data != 0) SSLAddSessionData(ctx); break; default: assert("Unknown State"); break; } return noErr; } OSStatus SSLPrepareAndQueueMessage(EncodeMessageFunc msgFunc, SSLContext *ctx) { OSStatus err; SSLRecord rec; if ((err = msgFunc(rec, ctx)) != 0) { SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); goto fail; } if (rec.contentType == SSL_RecordTypeHandshake) { if ((err = SSLHashSHA1.update(ctx->shaState, rec.contents)) != 0 || (err = SSLHashMD5.update(ctx->md5State, rec.contents)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); goto fail; } SSLLogHdskMsg((SSLHandshakeType)rec.contents.data[0], 1); } assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->writeRecord(rec, ctx)) != 0) goto fail; err = noErr; fail: SSLFreeBuffer(rec.contents, ctx); return err; } OSStatus SSL3ReceiveSSL2ClientHello(SSLRecord rec, SSLContext *ctx) { OSStatus err; if ((err = SSLInitMessageHashes(ctx)) != 0) return err; if ((err = SSLHashSHA1.update(ctx->shaState, rec.contents)) != 0 || (err = SSLHashMD5.update(ctx->md5State, rec.contents)) != 0) { SSLFatalSessionAlert(SSL_AlertInternalError, ctx); return err; } if ((err = SSLAdvanceHandshake(SSL_HdskClientHello, ctx)) != 0) return err; return noErr; } /* log changes in handshake state */ #ifndef NDEBUG #include char *hdskStateToStr(SSLHandshakeState state) { static char badStr[100]; switch(state) { case SSL_HdskStateUninit: return "Uninit"; case SSL_HdskStateServerUninit: return "ServerUninit"; case SSL_HdskStateClientUninit: return "ClientUninit"; case SSL_HdskStateGracefulClose: return "GracefulClose"; case SSL_HdskStateErrorClose: return "ErrorClose"; case SSL_HdskStateNoNotifyClose: return "NoNotifyClose"; case SSL_HdskStateServerHello: return "ServerHello"; case SSL_HdskStateServerHelloUnknownVersion: return "ServerHelloUnknownVersion"; case SSL_HdskStateKeyExchange: return "KeyExchange"; case SSL_HdskStateCert: return "Cert"; case SSL_HdskStateHelloDone: return "HelloDone"; case SSL_HdskStateClientCert: return "ClientCert"; case SSL_HdskStateClientKeyExchange: return "ClientKeyExchange"; case SSL_HdskStateClientCertVerify: return "ClientCertVerify"; case SSL_HdskStateChangeCipherSpec: return "ChangeCipherSpec"; case SSL_HdskStateFinished: return "Finished"; case SSL2_HdskStateClientMasterKey: return "SSL2_ClientMasterKey"; case SSL2_HdskStateClientFinished: return "SSL2_ClientFinished"; case SSL2_HdskStateServerHello: return "SSL2_ServerHello"; case SSL2_HdskStateServerVerify: return "SSL2_ServerVerify"; case SSL2_HdskStateServerFinished: return "SSL2_ServerFinished"; case SSL_HdskStateServerReady: return "SSL_ServerReady"; case SSL_HdskStateClientReady: return "SSL_ClientReady"; default: sprintf(badStr, "Unknown state (%d(d)", state); return badStr; } } void SSLChangeHdskState(SSLContext *ctx, SSLHandshakeState newState) { /* FIXME - this ifndef should not be necessary */ #ifndef NDEBUG sslHdskStateDebug("...hdskState = %s", hdskStateToStr(newState)); #endif ctx->state = newState; } /* log handshake messages */ static char *hdskMsgToStr(SSLHandshakeType msg) { static char badStr[100]; switch(msg) { case SSL_HdskHelloRequest: return "SSL_HdskHelloRequest"; case SSL_HdskClientHello: return "SSL_HdskClientHello"; case SSL_HdskServerHello: return "SSL_HdskServerHello"; case SSL_HdskCert: return "SSL_HdskCert"; case SSL_HdskServerKeyExchange: return "SSL_HdskServerKeyExchange"; case SSL_HdskCertRequest: return "SSL_HdskCertRequest"; case SSL_HdskServerHelloDone: return "SSL_HdskServerHelloDone"; case SSL_HdskCertVerify: return "SSL_HdskCertVerify"; case SSL_HdskClientKeyExchange: return "SSL_HdskClientKeyExchange"; case SSL_HdskFinished: return "SSL_HdskFinished"; case SSL_HdskNoCertAlert: return "SSL_HdskNoCertAlert"; default: sprintf(badStr, "Unknown state (%d(d)", msg); return badStr; } } void SSLLogHdskMsg(SSLHandshakeType msg, char sent) { sslHdskMsgDebug("---%s handshake msg %s", hdskMsgToStr(msg), (sent ? "sent" : "recv")); } #endif /* NDEBUG */