int32 psHmacSha1(unsigned char *key, uint32 keyLen, const unsigned char *buf, uint32 len, unsigned char *hash, unsigned char *hmacKey, uint32 *hmacKeyLen) { psHmacContext_t ctx; psDigestContext_t sha; /* Support for keys larger than 64 bytes. In this case, we take the hash of the key itself and use that instead. Inform the caller by updating the hmacKey and hmacKeyLen outputs */ if (keyLen > 64) { psSha1Init(&sha); psSha1Update(&sha, key, keyLen); *hmacKeyLen = psSha1Final(&sha, hash); memcpy(hmacKey, hash, *hmacKeyLen); } else { hmacKey = key; *hmacKeyLen = keyLen; } psHmacSha1Init(&ctx, hmacKey, *hmacKeyLen); psHmacSha1Update(&ctx, buf, len); return psHmacSha1Final(&ctx, hash); }
int32_t psHmacSha1(const unsigned char *key, uint16_t keyLen, const unsigned char *buf, uint32_t len, unsigned char hash[SHA1_HASHLEN], unsigned char *hmacKey, uint16_t *hmacKeyLen) { psSha1_t sha; /* Support for keys larger than 64 bytes. In this case, we take the hash of the key itself and use that instead. Inform the caller by updating the hmacKey and hmacKeyLen outputs */ if (keyLen > 64) { psSha1Init(&sha); psSha1Update(&sha, key, keyLen); psSha1Final(&sha, hash); *hmacKeyLen = SHA1_HASHLEN; memcpy(hmacKey, hash, *hmacKeyLen); } else { hmacKey = (unsigned char*)key; *hmacKeyLen = keyLen; } if (HMAC(EVP_sha1(), hmacKey, *hmacKeyLen, buf, len, hash, NULL) != NULL) { return PS_SUCCESS; } return PS_FAIL; }
/** Finalize output of the combined MD5-SHA1 The output is 36 bytes, first the 16 bytes MD5 then the 20 bytes SHA1 */ void psMd5Sha1Final(psMd5Sha1_t *md, unsigned char hash[MD5SHA1_HASHLEN]) { # ifdef CRYPTO_ASSERT psAssert(md && hash); # endif psMd5Final(&md->md5, hash); psSha1Final(&md->sha1, hash + MD5_HASHLEN); }
/* Combine the running hash of the handshake mesages with some constants and mix them up a bit more. Output the result to the given buffer. This data will be part of the Finished handshake message. */ int32 sslGenerateFinishedHash(psDigestContext_t *md5, psDigestContext_t *sha1, unsigned char *masterSecret, unsigned char *out, int32 sender) { psDigestContext_t omd5,osha1; unsigned char ihash[SHA1_HASH_SIZE]; /* md5Hash = MD5(master_secret + pad2 + MD5(handshake_messages + sender + master_secret + pad1)); */ if (sender >= 0) { psMd5Update(md5, (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } psMd5Update(md5, masterSecret, SSL_HS_MASTER_SIZE); psMd5Update(md5, pad1, sizeof(pad1)); psMd5Final(md5, ihash); psMd5Init(&omd5); psMd5Update(&omd5, masterSecret, SSL_HS_MASTER_SIZE); psMd5Update(&omd5, pad2, sizeof(pad2)); psMd5Update(&omd5, ihash, MD5_HASH_SIZE); psMd5Final(&omd5, out); /* The SHA1 hash is generated in the same way, except only 40 bytes of pad1 and pad2 are used. sha1Hash = SHA1(master_secret + pad2 + SHA1(handshake_messages + sender + master_secret + pad1)); */ if (sender >= 0) { psSha1Update(sha1, (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } psSha1Update(sha1, masterSecret, SSL_HS_MASTER_SIZE); psSha1Update(sha1, pad1, 40); psSha1Final(sha1, ihash); psSha1Init(&osha1); psSha1Update(&osha1, masterSecret, SSL_HS_MASTER_SIZE); psSha1Update(&osha1, pad2, 40); psSha1Update(&osha1, ihash, SHA1_HASH_SIZE); psSha1Final(&osha1, out + MD5_HASH_SIZE); return MD5_HASH_SIZE + SHA1_HASH_SIZE; }
int32 psHmacSha1Final(psHmacContext_t *ctx, unsigned char *hash) { psAssert(ctx != NULL); if (hash == NULL) { psTraceCrypto("NULL hash storage passed to psHmacSha1Final\n"); return PS_ARG_FAIL; } psSha1Final(&ctx->u.sha1, hash); psSha1Init(&ctx->u.sha1); psSha1Update(&ctx->u.sha1, ctx->pad, 64); psSha1Update(&ctx->u.sha1, hash, SHA1_HASH_SIZE); psSha1Final(&ctx->u.sha1, hash); memset(ctx->pad, 0x0, 64); return SHA1_HASH_SIZE; }
/* * Generates all key material. */ int32 sslDeriveKeys(ssl_t *ssl) { psDigestContext_t md5Ctx, sha1Ctx; unsigned char buf[MD5_HASH_SIZE + SHA1_HASH_SIZE]; unsigned char *tmp; uint32 i; /* If this session is resumed, we want to reuse the master secret to regenerate the key block with the new random values. */ if (ssl->flags & SSL_FLAGS_RESUMED) { goto skipPremaster; } /* master_secret = MD5(pre_master_secret + SHA('A' + pre_master_secret + ClientHello.random + ServerHello.random)) + MD5(pre_master_secret + SHA('BB' + pre_master_secret + ClientHello.random + ServerHello.random)) + MD5(pre_master_secret + SHA('CCC' + pre_master_secret + ClientHello.random + ServerHello.random)); */ tmp = ssl->sec.masterSecret; for (i = 0; i < 3; i++) { psSha1Init(&sha1Ctx); psSha1Update(&sha1Ctx, salt[i], i + 1); psSha1Update(&sha1Ctx, ssl->sec.premaster, ssl->sec.premasterSize); psSha1Update(&sha1Ctx, ssl->sec.clientRandom, SSL_HS_RANDOM_SIZE); psSha1Update(&sha1Ctx, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE); psSha1Final(&sha1Ctx, buf); psMd5Init(&md5Ctx); psMd5Update(&md5Ctx, ssl->sec.premaster, ssl->sec.premasterSize); psMd5Update(&md5Ctx, buf, SHA1_HASH_SIZE); psMd5Final(&md5Ctx, tmp); tmp += MD5_HASH_SIZE; } memset(buf, 0x0, MD5_HASH_SIZE + SHA1_HASH_SIZE); /* premaster is now allocated for DH reasons. Can free here */ psFree(ssl->sec.premaster); ssl->sec.premaster = NULL; ssl->sec.premasterSize = 0; skipPremaster: if (createKeyBlock(ssl, ssl->sec.clientRandom, ssl->sec.serverRandom, ssl->sec.masterSecret, SSL_HS_MASTER_SIZE) < 0) { psTraceInfo("Unable to create key block\n"); return PS_FAILURE; } return SSL_HS_MASTER_SIZE; }
void psHmacSha1Final(psHmacSha1_t *ctx, unsigned char hash[SHA1_HASHLEN]) { int32_t rc; #ifdef CRYPTO_ASSERT psAssert(ctx != NULL); if (hash == NULL) { psTraceCrypto("NULL hash storage passed to psHmacSha1Final\n"); return; } #endif psSha1Final(&ctx->sha1, hash); if ((rc = psSha1Init(&ctx->sha1)) < 0) { psAssert(rc >= 0); return; } psSha1Update(&ctx->sha1, ctx->pad, 64); psSha1Update(&ctx->sha1, hash, SHA1_HASHLEN); psSha1Final(&ctx->sha1, hash); memset(ctx->pad, 0x0, sizeof(ctx->pad)); }
/* TLS handshake has computation */ int32 tlsGenerateFinishedHash(ssl_t *ssl, psDigestContext_t *md5, psDigestContext_t *sha1, psDigestContext_t *sha256, unsigned char *masterSecret, unsigned char *out, int32 sender) { unsigned char tmp[FINISHED_LABEL_SIZE + MD5_HASH_SIZE + SHA1_HASH_SIZE]; if (sender >= 0) { memcpy(tmp, (sender & SSL_FLAGS_SERVER) ? LABEL_SERVER : LABEL_CLIENT, FINISHED_LABEL_SIZE); psMd5Final(md5, tmp + FINISHED_LABEL_SIZE); psSha1Final(sha1, tmp + FINISHED_LABEL_SIZE + MD5_HASH_SIZE); return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp, sizeof(tmp), out, TLS_HS_FINISHED_SIZE); } else { /* The handshake snapshot for client authentication is simply the appended MD5 and SHA1 hashes */ psMd5Final(md5, out); psSha1Final(sha1, out + MD5_HASH_SIZE); return MD5_HASH_SIZE + SHA1_HASH_SIZE; } return PS_FAILURE; /* Should not reach this */ }
/** Add entropy to the PRNG state @param in The data to add @param inlen Length of the data to add @param prng PRNG state to update */ int32 psYarrowAddEntropy(unsigned char *in, uint32 inlen, psYarrow_t *prng) { psDigestContext_t md; int32 err; if (in == NULL || prng == NULL) { return PS_ARG_FAIL; } #ifdef USE_SHA256 /* start the hash */ psSha256Init(&md); /* hash the current pool */ psSha256Update(&md, prng->pool, SHA256_HASH_SIZE); /* add the new entropy */ psSha256Update(&md, in, inlen); /* store result */ if ((err = psSha256Final(&md, prng->pool)) != SHA256_HASH_SIZE) { return err; } #else /* start the hash */ psSha1Init(&md); /* hash the current pool */ psSha1Update(&md, prng->pool, SHA1_HASH_SIZE); /* add the new entropy */ psSha1Update(&md, in, inlen); /* store result */ if ((err = psSha1Final(&md, prng->pool)) != SHA1_HASH_SIZE) { return err; } #endif return PS_SUCCESS; }
int32_t psHmacSha1(const unsigned char *key, uint16_t keyLen, const unsigned char *buf, uint32_t len, unsigned char hash[SHA1_HASHLEN], unsigned char *hmacKey, uint16_t *hmacKeyLen) { int32_t rc; union { psHmacSha1_t mac; psSha1_t md; } u; psHmacSha1_t *mac = &u.mac; psSha1_t *md = &u.md; /* Support for keys larger than 64 bytes. In this case, we take the hash of the key itself and use that instead. Inform the caller by updating the hmacKey and hmacKeyLen outputs */ if (keyLen > 64) { if ((rc = psSha1Init(md)) < 0) { return rc; } psSha1Update(md, key, keyLen); psSha1Final(md, hash); *hmacKeyLen = SHA1_HASHLEN; memcpy(hmacKey, hash, *hmacKeyLen); } else { hmacKey = (unsigned char *)key; /* @note typecasting from const */ *hmacKeyLen = keyLen; } if ((rc = psHmacSha1Init(mac, hmacKey, *hmacKeyLen)) < 0) { return rc; } psHmacSha1Update(mac, buf, len); psHmacSha1Final(mac, hash); return PS_SUCCESS; }
/* Generate the key block as follows. '+' indicates concatination. key_block = MD5(master_secret + SHA(`A' + master_secret + ServerHello.random + ClientHello.random)) + MD5(master_secret + SHA(`BB' + master_secret + ServerHello.random + ClientHello.random)) + MD5(master_secret + SHA(`CCC' + master_secret + ServerHello.random + ClientHello.random)) + [...]; */ static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom, unsigned char *serverRandom, unsigned char *masterSecret, uint32 secretLen) { psDigestContext_t md5Ctx, sha1Ctx; unsigned char buf[MD5_HASH_SIZE + SHA1_HASH_SIZE]; unsigned char *tmp; int32 ret = 0; uint32 i, keyIter, reqKeyLen; /* We must generate enough key material to fill the various keys */ reqKeyLen = 2 * ssl->cipher->macSize + 2 * ssl->cipher->keySize + 2 * ssl->cipher->ivSize; /* Find the right number of iterations to make the requested length key block */ keyIter = 1; while (MD5_HASH_SIZE * keyIter < reqKeyLen) { keyIter++; } if (keyIter > sizeof(salt)/sizeof(char*)) { psTraceIntInfo("Error: Not enough salt for key length %d\n", reqKeyLen); return PS_FAILURE; } tmp = ssl->sec.keyBlock; for (i = 0; i < keyIter; i++) { psSha1Init(&sha1Ctx); psSha1Update(&sha1Ctx, salt[i], i + 1); psSha1Update(&sha1Ctx, masterSecret, secretLen); psSha1Update(&sha1Ctx, serverRandom, SSL_HS_RANDOM_SIZE); psSha1Update(&sha1Ctx, clientRandom, SSL_HS_RANDOM_SIZE); psSha1Final(&sha1Ctx, buf); psMd5Init(&md5Ctx); psMd5Update(&md5Ctx, masterSecret, secretLen); psMd5Update(&md5Ctx, buf, SHA1_HASH_SIZE); psMd5Final(&md5Ctx, tmp); tmp += MD5_HASH_SIZE; ret += MD5_HASH_SIZE; } memset(buf, 0x0, MD5_HASH_SIZE + SHA1_HASH_SIZE); /* Client and server use different read/write values, with the Client write value being the server read value. */ if (ssl->flags & SSL_FLAGS_SERVER) { ssl->sec.rMACptr = ssl->sec.keyBlock; ssl->sec.wMACptr = ssl->sec.rMACptr + ssl->cipher->macSize; ssl->sec.rKeyptr = ssl->sec.wMACptr + ssl->cipher->macSize; ssl->sec.wKeyptr = ssl->sec.rKeyptr + ssl->cipher->keySize; ssl->sec.rIVptr = ssl->sec.wKeyptr + ssl->cipher->keySize; ssl->sec.wIVptr = ssl->sec.rIVptr + ssl->cipher->ivSize; } else { ssl->sec.wMACptr = ssl->sec.keyBlock; ssl->sec.rMACptr = ssl->sec.wMACptr + ssl->cipher->macSize; ssl->sec.wKeyptr = ssl->sec.rMACptr + ssl->cipher->macSize; ssl->sec.rKeyptr = ssl->sec.wKeyptr + ssl->cipher->keySize; ssl->sec.wIVptr = ssl->sec.rKeyptr + ssl->cipher->keySize; ssl->sec.rIVptr = ssl->sec.wIVptr + ssl->cipher->ivSize; } return ret; }
/* Parse DER encoded asn.1 RSA public key out of a certificate stream. We reach here with 'pp' pointing to the byte after the algorithm identifier. */ int32_t psRsaParseAsnPubKey(psPool_t *pool, const unsigned char **pp, psSize_t len, psRsaKey_t *key, unsigned char sha1KeyHash[SHA1_HASH_SIZE]) { # ifdef USE_SHA1 psDigestContext_t dc; # endif const unsigned char *p = *pp; RSA *rsa; psSize_t keylen; # ifndef USE_D2I psSize_t seqlen; # endif if (len < 1 || (*(p++) != ASN_BIT_STRING) || getAsnLength(&p, len - 1, &keylen)) { goto L_FAIL; } /* ignored bits field should be zero */ if (*p++ != 0) { goto L_FAIL; } keylen--; # ifdef USE_SHA1 /* A public key hash is used in PKI tools (OCSP, Trusted CA indication). Standard RSA form - SHA-1 hash of the value of the BIT STRING subjectPublicKey [excluding the tag, length, and number of unused bits] */ psSha1Init(&dc.sha1); psSha1Update(&dc.sha1, p, keylen); psSha1Final(&dc.sha1, sha1KeyHash); # endif # ifdef USE_D2I /* OpenSSL expects to parse after the ignored bits field */ if ((rsa = d2i_RSAPublicKey(NULL, &p, keylen)) == NULL) { goto L_FAIL; } # else /* We can manually create the structures as OpenSSL would */ rsa = RSA_new(); if (getAsnSequence(&p, keylen, &seqlen) < 0 || getBig(&p, seqlen, &rsa->n) < 0 || getBig(&p, seqlen, &rsa->e) < 0) { RSA_free(rsa); goto L_FAIL; } # endif /* RSA_print_fp(stdout, rsa, 0); */ *pp = p; *key = rsa; return PS_SUCCESS; L_FAIL: psTraceIntCrypto("psRsaParseAsnPubKey error on byte %d\n", p - *pp); return PS_PARSE_FAIL; }
void runDigestTime(psDigestContext_t *ctx, int32 chunk, int32 alg) { psTime_t start, end; unsigned char *dataChunk; unsigned char hashout[64]; int32 bytesSent, bytesToSend, round; #ifdef USE_HIGHRES_TIME int32 mod; int64 diffu; #else int32 diffm; #endif dataChunk = psMalloc(NULL, chunk); bytesToSend = (DATABYTES_AMOUNT / chunk) * chunk; bytesSent = 0; switch (alg) { #ifdef USE_SHA1 case SHA1_ALG: psGetTime(&start, NULL); while (bytesSent < bytesToSend) { psSha1Update(&ctx->sha1, dataChunk, chunk); bytesSent += chunk; } psSha1Final(&ctx->sha1, hashout); psGetTime(&end, NULL); break; #endif #ifdef USE_SHA256 case SHA256_ALG: psGetTime(&start, NULL); while (bytesSent < bytesToSend) { psSha256Update(&ctx->sha256, dataChunk, chunk); bytesSent += chunk; } psSha256Final(&ctx->sha256, hashout); psGetTime(&end, NULL); break; #endif #ifdef USE_SHA384 case SHA384_ALG: psGetTime(&start, NULL); while (bytesSent < bytesToSend) { psSha384Update(&ctx->sha384, dataChunk, chunk); bytesSent += chunk; } psSha384Final(&ctx->sha384, hashout); psGetTime(&end, NULL); break; #endif #ifdef USE_SHA512 case SHA512_ALG: psGetTime(&start, NULL); while (bytesSent < bytesToSend) { psSha512Update(&ctx->sha512, dataChunk, chunk); bytesSent += chunk; } psSha512Final(&ctx->sha512, hashout); psGetTime(&end, NULL); break; #endif #ifdef USE_MD5 case MD5_ALG: psGetTime(&start, NULL); while (bytesSent < bytesToSend) { psMd5Update(&ctx->md5, dataChunk, chunk); bytesSent += chunk; } psMd5Final(&ctx->md5, hashout); psGetTime(&end, NULL); break; #endif default: printf("Skipping Digest Tests\n"); return; } #ifdef USE_HIGHRES_TIME diffu = psDiffUsecs(start, end); round = (bytesToSend / diffu); mod = (bytesToSend % diffu); printf("%d byte chunks in %lld usecs total for rate of %d.%d MB/sec\n", chunk, (unsigned long long)diffu, round, mod); #else diffm = psDiffMsecs(start, end, NULL); round = (bytesToSend / diffm) / 1000; printf("%d byte chunks in %d msecs total for rate of %d MB/sec\n", chunk, diffm, round); #endif }
/* TLS handshake hash computation */ static int32 tlsGenerateFinishedHash(ssl_t *ssl, psDigestContext_t *md5, psDigestContext_t *sha1, psDigestContext_t *sha256, psDigestContext_t *sha384, unsigned char *masterSecret, unsigned char *out, int32 sender) { unsigned char tmp[FINISHED_LABEL_SIZE + SHA384_HASH_SIZE]; int32 tlsTmpSize; if (sender >= 0) { memcpy(tmp, (sender & SSL_FLAGS_SERVER) ? LABEL_SERVER : LABEL_CLIENT, FINISHED_LABEL_SIZE); tlsTmpSize = FINISHED_LABEL_SIZE + SHA1_HASH_SIZE + MD5_HASH_SIZE; #ifdef USE_TLS_1_2 if (ssl->flags & SSL_FLAGS_TLS_1_2) { if (ssl->cipher->flags & CRYPTO_FLAGS_SHA3) { #ifdef USE_SHA384 psSha384Final(sha384, tmp + FINISHED_LABEL_SIZE); return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp, FINISHED_LABEL_SIZE + SHA384_HASH_SIZE, out, TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA3); #endif } else { psSha256Final(sha256, tmp + FINISHED_LABEL_SIZE); return prf2(masterSecret, SSL_HS_MASTER_SIZE, tmp, FINISHED_LABEL_SIZE + SHA256_HASH_SIZE, out, TLS_HS_FINISHED_SIZE, CRYPTO_FLAGS_SHA2); } #ifndef USE_ONLY_TLS_1_2 } else { psMd5Final(md5, tmp + FINISHED_LABEL_SIZE); psSha1Final(sha1, tmp + FINISHED_LABEL_SIZE + MD5_HASH_SIZE); return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp, tlsTmpSize, out, TLS_HS_FINISHED_SIZE); #endif } #else psMd5Final(md5, tmp + FINISHED_LABEL_SIZE); psSha1Final(sha1, tmp + FINISHED_LABEL_SIZE + MD5_HASH_SIZE); return prf(masterSecret, SSL_HS_MASTER_SIZE, tmp, tlsTmpSize, out, TLS_HS_FINISHED_SIZE); #endif } else { /* Overloading this function to handle the client auth needs of handshake hashing. */ #ifdef USE_TLS_1_2 if (ssl->flags & SSL_FLAGS_TLS_1_2) { psSha256Final(sha256, out); #if defined(USE_SERVER_SIDE_SSL) && defined(USE_CLIENT_AUTH) #ifdef USE_SHA384 psSha384Final(sha384, ssl->sec.sha384Snapshot); #endif #ifndef USE_ONLY_TLS_1_2 psSha1Final(sha1, ssl->sec.sha1Snapshot); #endif #endif return SHA256_HASH_SIZE; #ifndef USE_ONLY_TLS_1_2 } else { psMd5Final(md5, out); psSha1Final(sha1, out + MD5_HASH_SIZE); return MD5_HASH_SIZE + SHA1_HASH_SIZE; #endif } #else /* The handshake snapshot for client authentication is simply the appended MD5 and SHA1 hashes */ psMd5Final(md5, out); psSha1Final(sha1, out + MD5_HASH_SIZE); return MD5_HASH_SIZE + SHA1_HASH_SIZE; #endif } return PS_FAILURE; /* Should not reach this */ }
/* It is possible the certificate verify message wants a non-SHA256 hash */ void sslSha1SnapshotHSHash(ssl_t *ssl, unsigned char *out) { psSha1Final(&ssl->sec.msgHashSha1, out); }