/* * Given a SecCertificateRef cert, obtain its public key as a SSLPubKey. * Caller must sslFreePubKey and free the SSLPubKey itself. */ extern OSStatus sslCopyPeerPubKey( SSLContext *ctx, SSLPubKey **pubKey) { OSStatus status = noErr; check(pubKey); check(ctx->peerSecTrust); if (!ctx->enableCertVerify) { SecTrustResultType result; require_noerr(status = SecTrustEvaluate(ctx->peerSecTrust, &result), errOut); } SecKeyRef key = SecTrustCopyPublicKey(ctx->peerSecTrust); if (!key) { sslErrorLog("sslCopyPeerPubKey: %s, ctx->peerSecTrust=%p\n", "SecTrustCopyPublicKey failed", (uintptr_t)ctx->peerSecTrust); return errSSLBadCert; } *pubKey = (SSLPubKey*)key; errOut: if (status) { sslErrorLog("sslCopyPeerPubKey: error %d\n", status); } return status; }
int SSLDecodeBufferList(uint8_t *p, size_t listLen, int itemLenSize, tls_buffer_list_t **list) { int err = 0; tls_buffer_list_t *first = NULL; tls_buffer_list_t *last = NULL; while (listLen > 0) { size_t itemLen; tls_buffer_list_t *item; if (listLen < itemLenSize) { sslErrorLog("SSLDecodeBufferList: length decode error 2\n"); err = errSSLProtocol; goto errOut; } itemLen = SSLDecodeInt(p,itemLenSize); p += itemLenSize; if (listLen < itemLen + itemLenSize) { sslErrorLog("SSLDecodeBufferList: length decode error 3\n"); err = errSSLProtocol; goto errOut; } if(itemLen==0) { sslErrorLog("SSLDecodeBufferList: lenght decode error 4 (empty item)\n"); err = errSSLProtocol; goto errOut; } item = (tls_buffer_list_t *)sslMalloc(sizeof(tls_buffer_list_t)); if(item == NULL) { err = errSSLAllocate; goto errOut; } if ((err = SSLAllocBuffer(&item->buffer, itemLen))) { sslFree(item); goto errOut; } item->next = NULL; memcpy(item->buffer.data, p, itemLen); p += itemLen; if(first==NULL) { first=item; last=item; } else { last->next=item; last=item; } listLen -= itemLenSize+itemLen; } *list = first; return 0; errOut: tls_free_buffer_list(first); return err; }
/* common for sslv3 and tlsv1, except for the computeMac callout */ int SSLVerifyMac(uint8_t type, SSLBuffer *data, uint8_t *compareMAC, struct SSLRecordInternalContext *ctx) { int err; uint8_t macData[SSL_MAX_DIGEST_LEN]; SSLBuffer secret, mac; secret.data = ctx->readCipher.macSecret; secret.length = ctx->readCipher.macRef->hash->digestSize; mac.data = macData; mac.length = ctx->readCipher.macRef->hash->digestSize; check(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->computeMac(type, *data, mac, &ctx->readCipher, ctx->readCipher.sequenceNum, ctx)) != 0) return err; if ((memcmp(mac.data, compareMAC, mac.length)) != 0) { sslErrorLog("SSLVerifyMac: Mac verify failure\n"); return errSSLRecordProtocol; } return 0; }
/* * Verify a chain of DER-encoded certs. * First cert in a chain is root; this must also be present * in ctx->trustedCerts. * * If arePeerCerts is true, host name verification is enabled and we * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise * we're just validating our own certs; no host name checking and * peerSecTrust is transient. */ OSStatus sslVerifyCertChain( SSLContext *ctx, const SSLCertificate *certChain, bool arePeerCerts) { OSStatus ortn = noErr; assert(certChain); /* No point checking our own certs, our clients can do that. */ if (!arePeerCerts) return noErr; CertVerifyReturn cvrtn; /* @@@ Add real cert checking. */ if (certChain->next) { DERItem subject, issuer; issuer.data = certChain->derCert.data; issuer.length = certChain->derCert.length; subject.data = certChain->next->derCert.data; subject.length = certChain->next->derCert.length; cvrtn = certVerify(&subject, &issuer); if (cvrtn != CVR_Success) ortn = errSSLBadCert; } else { sslErrorLog("***sslVerifyCertChain: only one cert in chain\n"); } return ortn; }
int tls_handshake_process(tls_handshake_t filter, const tls_buffer message, uint8_t contentType) { int err; switch (contentType) { case tls_record_type_Handshake: sslLogRxProtocolDebug("Handshake"); err = SSLProcessHandshakeRecord(message, filter); break; case tls_record_type_Alert: sslLogRxProtocolDebug("Alert"); err = SSLProcessAlert(message, filter); break; case tls_record_type_ChangeCipher: sslLogRxProtocolDebug("ChangeCipher"); err = SSLProcessChangeCipherSpec(message, filter); break; case tls_record_type_SSL2: sslLogRxProtocolDebug("SSL2"); err = SSLProcessSSL2Message(message, filter); break; default: sslLogRxProtocolDebug("Not a supported protocol message"); return errSSLProtocol; } if(err==errSSLUnexpectedRecord) err=DTLSRetransmit(filter); if(err) sslErrorLog("Error processing a message (ct=%d, err=%d)", contentType, err); return err; }
OSStatus sslRawVerify( SSLContext *ctx, SSLPubKey *pubKey, const uint8_t *plainText, size_t plainTextLen, const uint8_t *sig, size_t sigLen) // available { #if 0 RSAStatus rsaStatus; rsaStatus = RSA_SigVerify(&pubKey->rsaKey, RP_PKCS1, plainText, plainTextLen, sig, sigLen); return rsaStatus ? rsaStatusToSSL(rsaStatus) : noErr; #else OSStatus status = SecKeyRawVerify(SECKEYREF(pubKey), kSecPaddingPKCS1, plainText, plainTextLen, sig, sigLen); if (status) { sslErrorLog("sslRawVerify: SecKeyRawVerify failed (error %d)\n", status); } return status; #endif }
/* TLS 1.2 RSA signature */ OSStatus sslRsaSign( SSLContext *ctx, SSLPrivKey *privKey, const SecAsn1AlgId *algId, const uint8_t *plainText, size_t plainTextLen, uint8_t *sig, // mallocd by caller; RETURNED size_t sigLen, // available size_t *actualBytes) // RETURNED { size_t inOutSigLen = sigLen; assert(actualBytes != NULL); OSStatus status = SecKeySignDigest(SECKEYREF(privKey), algId, plainText, plainTextLen, sig, &inOutSigLen); if (status) { sslErrorLog("sslRsaSign: SecKeySignDigest failed (error %d)\n", status); } /* Since the KeyExchange already allocated modulus size bytes we'll use all of them. SecureTransport has always sent that many bytes, so we're not going to deviate, to avoid interoperability issues. */ if (!status && (inOutSigLen < sigLen)) { size_t offset = sigLen - inOutSigLen; memmove(sig + offset, sig, inOutSigLen); memset(sig, 0, offset); inOutSigLen = sigLen; } *actualBytes = inOutSigLen; return status; }
static OSStatus errorTranslate(int recordErr) { switch(recordErr) { case errSecSuccess: return errSecSuccess; case errSSLRecordInternal: return errSSLInternal; case errSSLRecordWouldBlock: return errSSLWouldBlock; case errSSLRecordProtocol: return errSSLProtocol; case errSSLRecordNegotiation: return errSSLNegotiation; case errSSLRecordClosedAbort: return errSSLClosedAbort; case errSSLRecordConnectionRefused: return errSSLConnectionRefused; case errSSLRecordDecryptionFail: return errSSLDecryptionFail; case errSSLRecordBadRecordMac: return errSSLBadRecordMac; case errSSLRecordRecordOverflow: return errSSLRecordOverflow; case errSSLRecordUnexpectedRecord: return errSSLUnexpectedRecord; default: sslErrorLog("unknown error code returned in sslErrorTranslate: %d\n", recordErr); return recordErr; } }
/* Convert a SecCertificateRef to an SSLCertificate * */ static OSStatus secCertToSslCert( SSLContext *ctx, SecCertificateRef certRef, SSLCertificate **sslCert) { CSSM_DATA certData; // struct is transient, referent owned by // Sec layer OSStatus ortn; SSLCertificate *thisSslCert = NULL; ortn = SecCertificateGetData(certRef, &certData); if(ortn) { sslErrorLog("SecCertificateGetData() returned %d\n", (int)ortn); return ortn; } thisSslCert = (SSLCertificate *)sslMalloc(sizeof(SSLCertificate)); if(thisSslCert == NULL) { return memFullErr; } if(SSLAllocBuffer(&thisSslCert->derCert, certData.Length, ctx)) { return memFullErr; } memcpy(thisSslCert->derCert.data, certData.Data, certData.Length); thisSslCert->derCert.length = certData.Length; *sslCert = thisSslCert; return noErr; }
int tls_record_decrypt(tls_record_t ctx, const tls_buffer input, tls_buffer *output, uint8_t *contentType) { int err; tls_buffer cipherFragment; uint8_t *charPtr; uint64_t seqNum; uint8_t ct; charPtr=input.data; check(input.length>=header_size(ctx)); if(input.length<header_size(ctx)) return errSSLRecordParam; ct = *charPtr++; #if 0 // We dont actually check the record protocol version tls_protocol_version pv; pv = SSLDecodeInt(charPtr, 2); #endif charPtr+=2; if(ctx->isDTLS) { seqNum = SSLDecodeUInt64(charPtr, 8); charPtr+=8; } cipherFragment.length = SSLDecodeInt(charPtr, 2); charPtr+=2; cipherFragment.data = charPtr; #if 0 // This is too strict for the record layer. if (ct < tls_record_type_V3_Smallest || ct > tls_record_type_V3_Largest) return errSSLRecordProtocol; if ((ctx->negProtocolVersion != tls_protocol_version_Undertermined) && (pv != ctx->negProtocolVersion)) { sslErrorLog("invalid record protocol version, expected = %04x, received = %04x", ctx->negProtocolVersion, pv); return errSSLRecordProtocol; // Invalid record version ? } #endif check(input.length>=header_size(ctx)+cipherFragment.length); if(input.length<header_size(ctx)+cipherFragment.length) { return errSSLRecordParam; // input buffer not enough data } if(ctx->isDTLS) { /* if the epoch of the record is different of current read cipher, just drop it */ if((seqNum>>48)!=(ctx->readCipher.sequenceNum>>48)) { return errSSLRecordUnexpectedRecord; } else { ctx->readCipher.sequenceNum=seqNum; } }
/* * Given an ECDSA public key in X509 format, extract the raw public key * bits in ECPOint format. */ OSStatus sslEcdsaPubKeyBits( CSSM_KEY_PTR pubKey, SSLBuffer *pubBits) /* data mallocd and RETURNED */ { SecAsn1CoderRef coder = NULL; CSSM_X509_SUBJECT_PUBLIC_KEY_INFO subjPubKeyInfo; OSStatus ortn = noErr; CSSM_KEYHEADER *hdr = &pubKey->KeyHeader; if(hdr->AlgorithmId != CSSM_ALGID_ECDSA) { sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->BlobType != CSSM_KEYBLOB_RAW) { /* No can do - this must be raw format, it came from the CL */ sslErrorLog("sslEcdsaPubKeyBits: bad peer key algorithm\n"); return errSSLProtocol; } if(hdr->Format != CSSM_KEYBLOB_RAW_FORMAT_X509) { sslErrorLog("sslEcdsaPubKeyBits: bad peer key format\n"); return errSSLProtocol; } /* KeyData is an encoded CSSM_X509_SUBJECT_PUBLIC_KEY_INFO */ ortn = SecAsn1CoderCreate(&coder); if(ortn) { return errSSLInternal; } /* subsequent errors to errOut: */ memset(&subjPubKeyInfo, 0, sizeof(subjPubKeyInfo)); ortn = SecAsn1DecodeData(coder, &pubKey->KeyData, kSecAsn1SubjectPublicKeyInfoTemplate, &subjPubKeyInfo); if(ortn) { printf("sslEcdsaPubKeyBits: error decoding public key\n"); goto errOut; } /* that key data is a BITSTRING */ ortn = SSLCopyBufferFromData(subjPubKeyInfo.subjectPublicKey.Data, subjPubKeyInfo.subjectPublicKey.Length >> 3, pubBits); errOut: SecAsn1CoderRelease(coder); return ortn; }
int SSLProcessCertificateStatus(tls_buffer message, tls_handshake_t ctx) { uint8_t status_type; uint8_t *p = message.data; assert(!ctx->isServer); if (message.length < 1) { sslErrorLog("SSLProcessCertificateStatus: message length decode error (1)\n"); return errSSLProtocol; } status_type = *p++; if(status_type!=SSL_CST_Ocsp) { return noErr; } if (message.length < 3) { sslErrorLog("SSLProcessCertificateStatus: message length decode error (2)\n"); return errSSLProtocol; } size_t OCSPResponseLen = SSLDecodeSize(p, 3); p+=3; if(OCSPResponseLen==0) { sslErrorLog("SSLProcessCertificateStatus: message length decode error (3)\n"); return errSSLProtocol; } if(OCSPResponseLen+4 != message.length) { sslErrorLog("SSLProcessCertificateStatus: message length decode error (4)\n"); return errSSLProtocol; } ctx->ocsp_response_received = true; SSLFreeBuffer(&ctx->ocsp_response); return SSLCopyBufferFromData(p, OCSPResponseLen, &ctx->ocsp_response); }
/* * Given a DER encoded DHParameterBlock, extract the prime and generator. * modulus and public exponent. * This will work with either PKCS-1 encoded DHParameterBlock or * openssl-style DHParameter. */ OSStatus sslDecodeDhParams( const SSLBuffer *blob, /* PKCS-1 encoded */ SSLBuffer *prime, /* data mallocd and RETURNED */ SSLBuffer *generator) /* data mallocd and RETURNED */ { SECStatus rv; OSStatus srtn; NSS_DHParameterBlock paramBlock = {}; PLArenaPool *pool; assert(blob != NULL); assert(prime != NULL); assert(generator != NULL); pool = PORT_NewArena(CHUNKSIZE_DEF); /* * Since the common case here is to decode a parameter block coming * over the wire, which is in openssl format, let's try that format first. */ rv = SEC_ASN1Decode(pool, ¶mBlock.params, kSecAsn1DHParameterTemplate, (const char *)blob->data, blob->length); if (rv != SECSuccess) { /* * OK, that failed when trying as a CDSA_formatted parameter * block DHParameterBlock). Openssl uses a subset of that, * a DHParameter. Try that instead. */ memset(¶mBlock, 0, sizeof(paramBlock)); rv = SEC_ASN1Decode(pool, ¶mBlock, kSecAsn1DHParameterBlockTemplate, (const char *)blob->data, blob->length); } if (rv != SECSuccess) { /* Ah well, we tried. */ sslErrorLog("sslDecodeDhParams: both CDSA and openssl format" "failed\n"); srtn = errSSLCrypto; } else { /* copy out components */ srtn = SSLCopyBufferFromData(paramBlock.params.prime.Data, paramBlock.params.prime.Length, prime); if(!srtn) { srtn = SSLCopyBufferFromData(paramBlock.params.base.Data, paramBlock.params.base.Length, generator); } } PORT_FreeArena(pool, PR_TRUE); return srtn; }
int SSLFreeBuffer(SSLBuffer *buf) { if(buf == NULL) { sslErrorLog("SSLFreeBuffer: NULL buf!\n"); check(0); return -1; } sslFree(buf->data); buf->data = NULL; buf->length = 0; return 0; }
int SSLReallocBuffer(SSLBuffer *buf, size_t newSize) { buf->data = (uint8_t *)sslRealloc(buf->data, buf->length, newSize); if(buf->data == NULL) { sslErrorLog("SSLReallocBuffer: NULL buf!\n"); check(0); buf->length = 0; return -1; } buf->length = newSize; return 0; }
/* * Given raw RSA key bits, cook up a SSLPubKey. Used in * Server-initiated key exchange. */ OSStatus sslGetPubKeyFromBits( SSLContext *ctx, const SSLBuffer *modulus, const SSLBuffer *exponent, SSLPubKey **pubKey) // mallocd and RETURNED { if (!pubKey) return paramErr; #if 0 SSLPubKey *key; RSAStatus rsaStatus; RSAPubKey apiKey = { modulus->data, modulus->length, NULL, 0, exponent->data, exponent->length }; key = sslMalloc(sizeof(*key)); rsaStatus = rsaInitPubGKey(&apiKey, &key->rsaKey); if (rsaStatus) { sslFree(key); return rsaStatusToSSL(rsaStatus); } *pubKey = key; return noErr; #else check(pubKey); SecRSAPublicKeyParams params = { modulus->data, modulus->length, exponent->data, exponent->length }; #if SSL_DEBUG sslDebugLog("Creating RSA pub key from modulus=%p len=%lu exponent=%p len=%lu\n", (uintptr_t)modulus->data, modulus->length, (uintptr_t)exponent->data, exponent->length); #endif SecKeyRef key = SecKeyCreateRSAPublicKey(NULL, (const uint8_t *)¶ms, sizeof(params), kSecKeyEncodingRSAPublicParams); if (!key) { sslErrorLog("sslGetPubKeyFromBits: SecKeyCreateRSAPublicKey failed\n"); return errSSLCrypto; } #if SSL_DEBUG size_t blocksize = SecKeyGetBlockSize(key); sslDebugLog("sslGetPubKeyFromBits: RSA pub key block size=%lu\n", blocksize); #endif *pubKey = (SSLPubKey*)key; return noErr; #endif }
int SSLCopyBufferFromData( const void *src, size_t len, SSLBuffer *dst) // data mallocd and returned { dst->data = sslAllocCopy((const uint8_t *)src, len); if(dst->data == NULL) { sslErrorLog("SSLCopyBufferFromData: NULL buf!\n"); check(0); return -1; } dst->length = len; return 0; }
int SSLAllocBuffer( SSLBuffer *buf, size_t length) { buf->data = (uint8_t *)sslMalloc(length); if(buf->data == NULL) { sslErrorLog("SSLAllocBuffer: NULL buf!\n"); check(0); buf->length = 0; return -1; } buf->length = length; return 0; }
/* SSLWriteRecord * Attempt to encrypt and queue an SSL record. */ OSStatus SSLWriteRecord(SSLRecord rec, SSLContext *ctx) { OSStatus err; err=errorTranslate(ctx->recFuncs->write(ctx->recCtx, rec)); switch(err) { case errSecSuccess: break; default: sslErrorLog("unexpected error code returned in SSLWriteRecord: %d\n", (int)err); break; } return err; }
/* SSLReadRecord * Attempt to read & decrypt an SSL record. * Record content should be freed using SSLFreeRecord */ OSStatus SSLReadRecord(SSLRecord *rec, SSLContext *ctx) { OSStatus err; err=errorTranslate(ctx->recFuncs->read(ctx->recCtx, rec)); switch(err) { case errSecSuccess: case errSSLWouldBlock: break; case errSSLUnexpectedRecord: DTLSRetransmit(ctx); break; case errSSLDecryptionFail: case errSSLBadRecordMac: /* We never send a Decryption Failed alert, instead we send the BadRecordMac alert */ /* This is TLS 1.1 compliant - Do it for all protocols versions. */ /* Except for DTLS where we do not send any alert. */ if(ctx->isDTLS) { /* This will ensure we try to read again before returning to the caller We do NOT want to use errSSLWouldBlock here, as this should only indicate the IO read callback status */ err=errSSLUnexpectedRecord; } else { SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx); } break; case errSSLInternal: SSLFatalSessionAlert(SSL_AlertInternalError, ctx); break; case errSSLRecordOverflow: SSLFatalSessionAlert(SSL_AlertRecordOverflow, ctx); break; case errSSLClosedAbort: case errSSLConnectionRefused: SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); break; default: sslErrorLog("unknown error code returned in SSLReadRecord: %d\n", (int)err); SSLFatalSessionAlert(SSL_AlertCloseNotify, ctx); break; } return err; }
/* TLS 1.2 RSA verify */ OSStatus sslRsaVerify( SSLContext *ctx, SSLPubKey *pubKey, const SecAsn1AlgId *algId, const uint8_t *plainText, size_t plainTextLen, const uint8_t *sig, size_t sigLen) // available { OSStatus status = SecKeyVerifyDigest(SECKEYREF(pubKey), algId, plainText, plainTextLen, sig, sigLen); if (status) { sslErrorLog("sslRsaVerify: SecKeyVerifyDigest failed (error %d)\n", status); } return status; }
OSStatus sslRsaDecrypt( SSLContext *ctx, SSLPrivKey *privKey, const uint32_t padding, const uint8_t *cipherText, size_t cipherTextLen, uint8_t *plainText, // mallocd by caller; RETURNED size_t plainTextLen, // available size_t *actualBytes) // RETURNED { #if 0 gi_uint16 giPlainTextLen = plainTextLen; RSAStatus rsaStatus; assert(actualBytes != NULL); rsaStatus = RSA_Decrypt(&privKey->rsaKey, RP_PKCS1, cipherText, cipherTextLen, plainText, &giPlainTextLen); *actualBytes = giPlainTextLen; return rsaStatus ? rsaStatusToSSL(rsaStatus) : noErr; #else size_t ptlen = plainTextLen; assert(actualBytes != NULL); OSStatus status = SecKeyDecrypt(SECKEYREF(privKey), padding, cipherText, cipherTextLen, plainText, &ptlen); *actualBytes = ptlen; if (status) { sslErrorLog("sslRsaDecrypt: SecKeyDecrypt failed (error %d)\n", status); } return status; #endif }
int SSLAllocCopyBuffer( const SSLBuffer *src, SSLBuffer **dst) // buffer and data mallocd and returned { int serr; SSLBuffer *rtn = (SSLBuffer *)sslMalloc(sizeof(SSLBuffer)); if(rtn == NULL) { sslErrorLog("SSLAllocCopyBuffer: NULL buf!\n"); check(0); return -1; } serr = SSLCopyBuffer(src, rtn); if(serr) { sslFree(rtn); } else { *dst = rtn; } return serr; }
static const struct ccdigest_info *sslCipherSuiteGetDigestInfo(uint16_t selectedCipher) { HMAC_Algs alg = sslCipherSuiteGetMacAlgorithm(selectedCipher); switch (alg) { case HA_Null: return &null_di; case HA_MD5: return ccmd5_di(); case HA_SHA1: return ccsha1_di(); case HA_SHA256: return ccsha256_di(); case HA_SHA384: return ccsha384_di(); default: sslErrorLog("Invalid hashAlgorithm %d", alg); check(0); return NULL; } }
static const HashHmacReference *sslCipherSuiteGetHashHmacReference(uint16_t selectedCipher) { HMAC_Algs alg = sslCipherSuiteGetMacAlgorithm(selectedCipher); switch (alg) { case HA_Null: return &HashHmacNull; case HA_MD5: return &HashHmacMD5; case HA_SHA1: return &HashHmacSHA1; case HA_SHA256: return &HashHmacSHA256; case HA_SHA384: return &HashHmacSHA384; default: sslErrorLog("Invalid hashAlgorithm %d", alg); check(0); return &HashHmacNull; } }
OSStatus SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams, uint8_t *signature, UInt16 signatureLen) { OSStatus err; uint8_t buf[SSL_MAX_DIGEST_LEN]; const HashReference *hash; hash = isRsa ? &SSLHashMD5SHA1 : &SSLHashSHA1; SSLCalculateServerKeyExchangeHash(hash, ctx, signedParams, buf); err = sslRawVerify(ctx, ctx->peerPubKey, buf, hash->digestSize, signature, signatureLen); if (err) { sslErrorLog("SSLVerifySignedServerKeyExchange: sslRawVerify " "returned %d\n", (int)err); } return err; }
int SSLProcessCertificateVerify(tls_buffer message, tls_handshake_t ctx) { int err; UInt8 hashData[SSL_MAX_DIGEST_LEN]; size_t signatureLen; tls_buffer hashDataBuf; uint8_t *charPtr = message.data; uint8_t *endCp = charPtr + message.length; tls_signature_and_hash_algorithm sigAlg = {0,}; if (sslVersionIsLikeTls12(ctx)) { /* Parse the algorithm field added in TLS1.2 */ if((charPtr+2) > endCp) { sslErrorLog("SSLProcessCertificateVerify: msg len error 1\n"); return errSSLProtocol; } sigAlg.hash = *charPtr++; sigAlg.signature = *charPtr++; } if ((charPtr + 2) > endCp) { sslErrorLog("SSLProcessCertificateVerify: msg len error\n"); return errSSLProtocol; } signatureLen = SSLDecodeSize(charPtr, 2); charPtr += 2; if ((charPtr + signatureLen) > endCp) { sslErrorLog("SSLProcessCertificateVerify: sig len error 1\n"); return errSSLProtocol; } hashDataBuf.data = hashData; hashDataBuf.length = SSL_MAX_DIGEST_LEN; assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, &hashDataBuf, sigAlg.hash)) != 0) goto fail; if (sslVersionIsLikeTls12(ctx)) { if(sigAlg.signature==tls_signature_algorithm_RSA) { err = sslRsaVerify(&ctx->peerPubKey, sigAlg.hash, hashData, hashDataBuf.length, charPtr, signatureLen); } else { err = sslRawVerify(&ctx->peerPubKey, hashData, hashDataBuf.length, charPtr, signatureLen); } } else { /* sslRawVerify does the decrypt & compare for us in one shot. */ err = sslRawVerify(&ctx->peerPubKey, hashData, // data to verify hashDataBuf.length, charPtr, // signature signatureLen); } if(err) { SSLFatalSessionAlert(SSL_AlertDecryptError, ctx); goto fail; } err = errSSLSuccess; fail: return err; }
int SSLEncodeCertificateVerify(tls_buffer *certVerify, tls_handshake_t ctx) { int err; UInt8 hashData[SSL_MAX_DIGEST_LEN]; tls_buffer hashDataBuf; size_t len; size_t outputLen; UInt8 *charPtr; int head; size_t maxSigLen; certVerify->data = 0; hashDataBuf.data = hashData; hashDataBuf.length = SSL_MAX_DIGEST_LEN; assert(ctx->signingPrivKeyRef != NULL); err = sslGetMaxSigSize(ctx->signingPrivKeyRef, &maxSigLen); if(err) { goto fail; } tls_signature_and_hash_algorithm sigAlg = {0,}; switch(ctx->signingPrivKeyRef->desc.type) { case tls_private_key_type_rsa: sigAlg.signature = tls_signature_algorithm_RSA; break; case tls_private_key_type_ecdsa: sigAlg.signature = tls_signature_algorithm_ECDSA; if (ctx->negProtocolVersion <= tls_protocol_version_SSL_3) { return errSSLInternal; } break; default: /* shouldn't be here */ assert(0); return errSSLInternal; } assert(ctx->negProtocolVersion >= tls_protocol_version_SSL_3); head = SSLHandshakeHeaderSize(ctx); outputLen = maxSigLen + head + 2; // Note: this is only used for TLS 1.2 if (sslVersionIsLikeTls12(ctx)) { err=FindCertSigAlg(ctx, &sigAlg); if(err) goto fail; outputLen += 2; ctx->certSigAlg = sigAlg; // Save for metrics reporting. } assert(ctx->sslTslCalls != NULL); if ((err = ctx->sslTslCalls->computeCertVfyMac(ctx, &hashDataBuf, sigAlg.hash)) != 0) goto fail; if ((err = SSLAllocBuffer(certVerify, outputLen)) != 0) goto fail; /* Sign now to get the actual length */ charPtr = certVerify->data+head; if (sslVersionIsLikeTls12(ctx)) { *charPtr++ = sigAlg.hash; *charPtr++ = sigAlg.signature; switch (sigAlg.hash) { case tls_hash_algorithm_SHA512: case tls_hash_algorithm_SHA384: case tls_hash_algorithm_SHA256: case tls_hash_algorithm_SHA1: break; default: sslErrorLog("SSLEncodeCertificateVerify: unsupported signature hash algorithm (%d)\n", sigAlg.hash); assert(0); // if you get here, something is wrong in FindCertSigAlg err=errSSLInternal; goto fail; } if (sigAlg.signature == tls_signature_algorithm_RSA) { err = sslRsaSign(ctx->signingPrivKeyRef, sigAlg.hash, hashData, hashDataBuf.length, charPtr+2, maxSigLen, &outputLen); } else { err = sslEcdsaSign(ctx->signingPrivKeyRef, hashData, hashDataBuf.length, charPtr+2, maxSigLen, &outputLen); } len=outputLen+2+2; } else { err = sslRawSign(ctx->signingPrivKeyRef, hashData, // data to sign hashDataBuf.length, // Data to sign size charPtr+2, // signature destination maxSigLen, // we mallocd len+head+2 &outputLen); len = outputLen+2; } if(err) { sslErrorLog("SSLEncodeCertificateVerify: unable to sign data (error %d)\n", (int)err); goto fail; } // At this point: // len = message length // outputlen = sig length certVerify->length = len + head; /* charPtr point at the len field here */ SSLEncodeSize(charPtr, outputLen, 2); SSLEncodeHandshakeHeader(ctx, certVerify, SSL_HdskCertVerify, len); err = errSSLSuccess; fail: return err; }
int SSLProcessCertificateRequest(tls_buffer message, tls_handshake_t ctx) { unsigned i; unsigned typeCount; unsigned shListLen = 0; UInt8 *charPtr; unsigned dnListLen; unsigned dnLen; tls_buffer dnBuf; DNListElem *dn; int err; /* * Cert request only happens in during client authentication. * Application can send a client cert if they have an appropriate one. * coreTLS does not ensure the client cert is appropriate. */ unsigned minLen = (sslVersionIsLikeTls12(ctx)) ? 5 : 3; if (message.length < minLen) { sslErrorLog("SSLProcessCertificateRequest: length decode error 1\n"); return errSSLProtocol; } charPtr = message.data; typeCount = *charPtr++; if ((typeCount < 1) || (message.length < minLen + typeCount)) { sslErrorLog("SSLProcessCertificateRequest: length decode error 2\n"); return errSSLProtocol; } /* Update the server-specified auth types */ sslFree(ctx->clientAuthTypes); ctx->numAuthTypes = typeCount; ctx->clientAuthTypes = (tls_client_auth_type *) sslMalloc(ctx->numAuthTypes * sizeof(tls_client_auth_type)); if(ctx->clientAuthTypes==NULL) return errSSLInternal; for(i=0; i<ctx->numAuthTypes; i++) { sslLogNegotiateDebug("===Server specifies authType %d", (int)(*charPtr)); ctx->clientAuthTypes[i] = (tls_client_auth_type)(*charPtr++); } if (sslVersionIsLikeTls12(ctx)) { /* Parse the supported_signature_algorithms field added in TLS1.2 */ shListLen = SSLDecodeInt(charPtr, 2); charPtr += 2; if ((shListLen < 2) || (message.length < minLen + typeCount + shListLen)) { sslErrorLog("SSLProcessCertificateRequest: length decode error 3\n"); return errSSLProtocol; } if (shListLen & 1) { sslErrorLog("SSLProcessCertificateRequest: signAlg len odd\n"); return errSSLProtocol; } sslFree(ctx->peerSigAlgs); ctx->numPeerSigAlgs = shListLen / 2; ctx->peerSigAlgs = (tls_signature_and_hash_algorithm *) sslMalloc((ctx->numPeerSigAlgs) * sizeof(tls_signature_and_hash_algorithm)); if(ctx->peerSigAlgs==NULL) return errSSLInternal; for(i=0; i<ctx->numPeerSigAlgs; i++) { ctx->peerSigAlgs[i].hash = *charPtr++; ctx->peerSigAlgs[i].signature = *charPtr++; sslLogNegotiateDebug("===Server specifies sigAlg %d %d", ctx->peerSigAlgs[i].hash, ctx->peerSigAlgs[i].signature); } } /* Update the acceptable DNList */ SSLFreeDNList(ctx->acceptableDNList); ctx->acceptableDNList=NULL; dnListLen = SSLDecodeInt(charPtr, 2); charPtr += 2; if (message.length != minLen + typeCount + shListLen + 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)))) return err; dn = (DNListElem*)dnBuf.data; if ((err = SSLAllocBuffer(&dn->derDN, dnLen))) { SSLFreeBuffer(&dnBuf); 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); return errSSLSuccess; }
int SSLProcessCertificate(tls_buffer message, tls_handshake_t ctx) { size_t listLen; UInt8 *p; int err = 0; SSLCertificate *certChain; if (message.length < 3) { sslErrorLog("SSLProcessCertificate: message length decode error\n"); return errSSLProtocol; } p = message.data; listLen = SSLDecodeInt(p,3); p += 3; if (listLen + 3 != message.length) { sslErrorLog("SSLProcessCertificate: length decode error 1\n"); return errSSLProtocol; } // Note: An empty certificate list (listLen==0) is allowed by the TLS RFC, // but empty certificates (certLen==0) are not. Section 7.4.2 in RFC 5246 // defines the message syntax as such: // // opaque ASN.1Cert<1..2^24-1>; // // struct { // ASN.1Cert certificate_list<0..2^24-1>; // } Certificate; // // Note the difference between <1..2^24-1> and <0..2^24-1> // if((err = SSLDecodeBufferList(p, listLen, 3, (tls_buffer_list_t **)&certChain))) { return err; } p+=listLen; /* Do not accept a different server cert during renegotiation unless allowed */ if(!ctx->allowServerIdentityChange && ctx->peerCert && !CertificateChainEqual(ctx->peerCert, certChain)) { sslErrorLog("Illegal server identity change during renegotiation\n"); SSLFreeCertificates(certChain); return errSSLProtocol; } if (ctx->peerCert == NULL && __ssl_debug_enabled("sslLogNegotiateDebug")) { debug_log_chain("sslLogNegotiateDebug", certChain); } /* Free certs if they already exist */ SSLFreeCertificates(ctx->peerCert); ctx->peerCert=certChain; assert(p == message.data + message.length); /* Don't fail here if peerCert is NULL. An empty Certificate message is valid in some cases. The rest of the stack will handle it. */ return err; }