/* * Generates all key material. */ int32 sslDeriveKeys(ssl_t *ssl) { sslMd5Context_t md5Ctx; sslSha1Context_t sha1Ctx; unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE]; unsigned char *tmp; int32 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++) { matrixSha1Init(&sha1Ctx); matrixSha1Update(&sha1Ctx, salt[i], i + 1); matrixSha1Update(&sha1Ctx, ssl->sec.premaster, ssl->sec.premasterSize); matrixSha1Update(&sha1Ctx, ssl->sec.clientRandom, SSL_HS_RANDOM_SIZE); matrixSha1Update(&sha1Ctx, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE); matrixSha1Final(&sha1Ctx, buf); matrixMd5Init(&md5Ctx); matrixMd5Update(&md5Ctx, ssl->sec.premaster, ssl->sec.premasterSize); matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE); matrixMd5Final(&md5Ctx, tmp); tmp += SSL_MD5_HASH_SIZE; } memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_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) { matrixStrDebugMsg("Unable to create key block\n", NULL); return -1; } return SSL_HS_MASTER_SIZE; }
/* SSLv3 uses a method similar to HMAC to generate the MD5 message MAC. For MD5, 48 bytes of the pad are used. MD5(MAC_write_secret + pad2 + MD5(MAC_write_secret + pad1 + seq_num + length + content)); */ int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq, unsigned char type, unsigned char *data, int32 len, unsigned char *mac) { sslMd5Context_t md5; unsigned char ihash[SSL_MD5_HASH_SIZE]; int32 i; matrixMd5Init(&md5); matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE); matrixMd5Update(&md5, pad1, 48); matrixMd5Update(&md5, seq, 8); ihash[0] = type; ihash[1] = (len & 0xFF00) >> 8; ihash[2] = len & 0xFF; matrixMd5Update(&md5, ihash, 3); matrixMd5Update(&md5, data, len); matrixMd5Final(&md5, ihash); matrixMd5Init(&md5); matrixMd5Update(&md5, key, SSL_MD5_HASH_SIZE); matrixMd5Update(&md5, pad2, 48); matrixMd5Update(&md5, ihash, SSL_MD5_HASH_SIZE); matrixMd5Final(&md5, mac); /* Increment sequence number */ for (i = 7; i >= 0; i--) { seq[i]++; if (seq[i] != 0) { break; } } return SSL_MD5_HASH_SIZE; }
/* 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(sslMd5Context_t *md5, sslSha1Context_t *sha1, unsigned char *masterSecret, unsigned char *out, int32 sender) { sslMd5Context_t omd5; sslSha1Context_t osha1; unsigned char ihash[SSL_SHA1_HASH_SIZE]; /* md5Hash = MD5(master_secret + pad2 + MD5(handshake_messages + sender + master_secret + pad1)); */ if (sender >= 0) { matrixMd5Update(md5, (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } matrixMd5Update(md5, masterSecret, SSL_HS_MASTER_SIZE); matrixMd5Update(md5, pad1, sizeof(pad1)); matrixMd5Final(md5, ihash); matrixMd5Init(&omd5); matrixMd5Update(&omd5, masterSecret, SSL_HS_MASTER_SIZE); matrixMd5Update(&omd5, pad2, sizeof(pad2)); matrixMd5Update(&omd5, ihash, SSL_MD5_HASH_SIZE); matrixMd5Final(&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) { matrixSha1Update(sha1, (sender & SSL_FLAGS_SERVER) ? SENDER_SERVER : SENDER_CLIENT, 4); } matrixSha1Update(sha1, masterSecret, SSL_HS_MASTER_SIZE); matrixSha1Update(sha1, pad1, 40); matrixSha1Final(sha1, ihash); matrixSha1Init(&osha1); matrixSha1Update(&osha1, masterSecret, SSL_HS_MASTER_SIZE); matrixSha1Update(&osha1, pad2, 40); matrixSha1Update(&osha1, ihash, SSL_SHA1_HASH_SIZE); matrixSha1Final(&osha1, out + SSL_MD5_HASH_SIZE); return SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE; }
/* Initialize the SHA1 and MD5 hash contexts for the handshake messages */ int32 sslInitHSHash(ssl_t *ssl) { matrixSha1Init(&ssl->sec.msgHashSha1); matrixMd5Init(&ssl->sec.msgHashMd5); return 0; }
/* Parse an X509 ASN.1 certificate stream http://www.faqs.org/rfcs/rfc2459.html section 4.1 */ int32 matrixX509ParseCert(psPool_t *pool, unsigned char *pp, int32 size, sslRsaCert_t **outcert) { sslRsaCert_t *cert; sslMd5Context_t md5Ctx; sslSha1Context_t sha1Ctx; unsigned char *p, *end, *certStart, *certEnd; int32 certLen, len, parsing; #ifdef USE_MD2 sslMd2Context_t md2Ctx; #endif /* USE_MD2 */ /* Allocate the cert structure right away. User MUST always call matrixX509FreeCert regardless of whether this function succeeds. memset is important because the test for NULL is what is used to determine what to free */ *outcert = cert = psMalloc(pool, sizeof(sslRsaCert_t)); if (cert == NULL) { return -8; /* SSL_MEM_ERROR */ } memset(cert, '\0', sizeof(sslRsaCert_t)); p = pp; end = p + size; /* Certificate ::= SEQUENCE { tbsCertificate TBSCertificate, signatureAlgorithm AlgorithmIdentifier, signatureValue BIT STRING } */ parsing = 1; while (parsing) { if (getSequence(&p, (int32)(end - p), &len) < 0) { matrixStrDebugMsg("Initial cert parse error\n", NULL); return -1; } certStart = p; /* TBSCertificate ::= SEQUENCE { version [0] EXPLICIT Version DEFAULT v1, serialNumber CertificateSerialNumber, signature AlgorithmIdentifier, issuer Name, validity Validity, subject Name, subjectPublicKeyInfo SubjectPublicKeyInfo, issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, -- If present, version shall be v2 or v3 extensions [3] EXPLICIT Extensions OPTIONAL -- If present, version shall be v3 } */ if (getSequence(&p, (int32)(end - p), &len) < 0) { matrixStrDebugMsg("ASN sequence parse error\n", NULL); return -1; } certEnd = p + len; certLen = (int32)(certEnd - certStart); /* Version ::= INTEGER { v1(0), v2(1), v3(2) } */ if (getExplicitVersion(&p, (int32)(end - p), 0, &cert->version) < 0) { matrixStrDebugMsg("ASN version parse error\n", NULL); return -1; } if (cert->version != 2) { matrixIntDebugMsg("Warning: non-v3 certificate version: %d\n", cert->version); } /* CertificateSerialNumber ::= INTEGER */ if (getSerialNum(pool, &p, (int32)(end - p), &cert->serialNumber, &cert->serialNumberLen) < 0) { matrixStrDebugMsg("ASN serial number parse error\n", NULL); return -1; } /* AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } */ if (getAlgorithmIdentifier(&p, (int32)(end - p), &cert->certAlgorithm, 0) < 0) { return -1; } /* Name ::= CHOICE { RDNSequence } RDNSequence ::= SEQUENCE OF RelativeDistinguishedName RelativeDistinguishedName ::= SET OF AttributeTypeAndValue AttributeTypeAndValue ::= SEQUENCE { type AttributeType, value AttributeValue } AttributeType ::= OBJECT IDENTIFIER AttributeValue ::= ANY DEFINED BY AttributeType */ if (getDNAttributes(pool, &p, (int32)(end - p), &cert->issuer) < 0) { return -1; } /* Validity ::= SEQUENCE { notBefore Time, notAfter Time } */ if (getValidity(pool, &p, (int32)(end - p), &cert->notBefore, &cert->notAfter) < 0) { return -1; } /* Subject DN */ if (getDNAttributes(pool, &p, (int32)(end - p), &cert->subject) < 0) { return -1; } /* SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING } */ if (getSequence(&p, (int32)(end - p), &len) < 0) { return -1; } if (getAlgorithmIdentifier(&p, (int32)(end - p), &cert->pubKeyAlgorithm, 1) < 0) { return -1; } if (getPubKey(pool, &p, (int32)(end - p), &cert->publicKey) < 0) { return -1; } /* As the next three values are optional, we can do a specific test here */ if (*p != (ASN_SEQUENCE | ASN_CONSTRUCTED)) { if (getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_ISSUER_ID, &cert->uniqueUserId, &cert->uniqueUserIdLen) < 0 || getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_SUBJECT_ID, &cert->uniqueSubjectId, &cert->uniqueSubjectIdLen) < 0 || getExplicitExtensions(pool, &p, (int32)(end - p), EXPLICIT_EXTENSION, &cert->extensions) < 0) { matrixStrDebugMsg("There was an error parsing a certificate\n", NULL); matrixStrDebugMsg("extension. This is likely caused by an\n", NULL); matrixStrDebugMsg("extension format that is not currently\n", NULL); matrixStrDebugMsg("recognized. Please email [email protected]\n", NULL); matrixStrDebugMsg("to add support for the extension.\n\n", NULL); return -1; } } /* This is the end of the cert. Do a check here to be certain */ if (certEnd != p) { return -1; } /* Certificate signature info */ if (getAlgorithmIdentifier(&p, (int32)(end - p), &cert->sigAlgorithm, 0) < 0) { return -1; } /* Signature algorithm must match that specified in TBS cert */ if (cert->certAlgorithm != cert->sigAlgorithm) { matrixStrDebugMsg("Parse error: mismatched signature type\n", NULL); return -1; } /* Compute the hash of the cert here for CA validation */ if (cert->certAlgorithm == OID_RSA_MD5) { matrixMd5Init(&md5Ctx); matrixMd5Update(&md5Ctx, certStart, certLen); matrixMd5Final(&md5Ctx, cert->sigHash); } else if (cert->certAlgorithm == OID_RSA_SHA1) { matrixSha1Init(&sha1Ctx); matrixSha1Update(&sha1Ctx, certStart, certLen); matrixSha1Final(&sha1Ctx, cert->sigHash); } #ifdef USE_MD2 else if (cert->certAlgorithm == OID_RSA_MD2) { matrixMd2Init(&md2Ctx); matrixMd2Update(&md2Ctx, certStart, certLen); matrixMd2Final(&md2Ctx, cert->sigHash); } #endif /* USE_MD2 */ if (getSignature(pool, &p, (int32)(end - p), &cert->signature, &cert->signatureLen) < 0) { return -1; } /* The ability to parse additional chained certs is a PKI product feature addition. Chaining in MatrixSSL is handled internally. */ if (p != end) { cert->next = psMalloc(pool, sizeof(sslRsaCert_t)); cert = cert->next; memset(cert, '\0', sizeof(sslRsaCert_t)); } else { parsing = 0; } } return (int32)(p - pp); }
/* X509v3 extensions */ static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp, int32 inlen, int32 expVal, v3extensions_t *extensions) { unsigned char *p = *pp, *end; unsigned char *extEnd, *extStart; int32 len, noid, tmpLen, critical, fullExtLen; unsigned char oid[SSL_MD5_HASH_SIZE]; sslMd5Context_t md5ctx; end = p + inlen; if (inlen < 1) { return -1; } /* Not treating this as an error because it is optional. */ if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | expVal)) { return 0; } p++; if (asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) < len) { return -1; } /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, extnValue OCTET STRING } */ if (getSequence(&p, (int32)(end - p), &len) < 0) { return -1; } extEnd = p + len; while ((p != extEnd) && *p == (ASN_SEQUENCE | ASN_CONSTRUCTED)) { if (getSequence(&p, (int32)(extEnd - p), &fullExtLen) < 0) { return -1; } extStart = p; /* Conforming CAs MUST support key identifiers, basic constraints, key usage, and certificate policies extensions id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } 133 id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } 131 */ if (extEnd - p < 1 || *p++ != ASN_OID) { return -1; } if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || (extEnd - p) < len) { return -1; } /* Send the OID through a digest to get the unique id */ matrixMd5Init(&md5ctx); while (len-- > 0) { matrixMd5Update(&md5ctx, p, sizeof(char)); p++; } matrixMd5Final(&md5ctx, oid); noid = lookupExt(oid); /* Possible boolean value here for 'critical' id. It's a failure if a critical extension is found that is not supported */ critical = 0; if (*p == ASN_BOOLEAN) { p++; if (*p++ != 1) { matrixStrDebugMsg("Error parsing cert extension\n", NULL); return -1; } if (*p++ > 0) { critical = 1; } } if (extEnd - p < 1 || (*p++ != ASN_OCTET_STRING) || asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || extEnd - p < len) { matrixStrDebugMsg("Expecting OCTET STRING in ext parse\n", NULL); return -1; } switch (noid) { /* BasicConstraints ::= SEQUENCE { cA BOOLEAN DEFAULT FALSE, pathLenConstraint INTEGER (0..MAX) OPTIONAL } */ case EXT_BASIC_CONSTRAINTS: if (getSequence(&p, (int32)(extEnd - p), &len) < 0) { return -1; } /* "This goes against PKIX guidelines but some CAs do it and some software requires this to avoid interpreting an end user certificate as a CA." - OpenSSL certificate configuration doc basicConstraints=CA:FALSE */ if (len == 0) { break; } if (extEnd - p < 3) { return -1; } if (*p++ != ASN_BOOLEAN) { return -1; } if (*p++ != 1) { return -1; } extensions->bc.ca = *p++; /* Now need to check if there is a path constraint. Only makes sense if cA is true. If it's missing, there is no limit to the cert path */ if (*p == ASN_INTEGER) { if (getInteger(&p, (int32)(extEnd - p), &(extensions->bc.pathLenConstraint)) < 0) { return -1; } } else { extensions->bc.pathLenConstraint = -1; } break; case EXT_ALT_SUBJECT_NAME: if (getSequence(&p, (int32)(extEnd - p), &len) < 0) { return -1; } /* Looking only for DNS, URI, and email here to support FQDN for Web clients FUTURE: Support all subject alt name members GeneralName ::= CHOICE { otherName [0] OtherName, rfc822Name [1] IA5String, dNSName [2] IA5String, x400Address [3] ORAddress, directoryName [4] Name, ediPartyName [5] EDIPartyName, uniformResourceIdentifier [6] IA5String, iPAddress [7] OCTET STRING, registeredID [8] OBJECT IDENTIFIER } */ while (len > 0) { if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) { p++; tmpLen = *p++; if (extEnd - p < tmpLen) { return -1; } extensions->san.dns = psMalloc(pool, tmpLen + 1); if (extensions->san.dns == NULL) { return -8; /* SSL_MEM_ERROR */ } memset(extensions->san.dns, 0x0, tmpLen + 1); memcpy(extensions->san.dns, p, tmpLen); } else if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 6)) { p++; tmpLen = *p++; if (extEnd - p < tmpLen) { return -1; } extensions->san.uri = psMalloc(pool, tmpLen + 1); if (extensions->san.uri == NULL) { return -8; /* SSL_MEM_ERROR */ } memset(extensions->san.uri, 0x0, tmpLen + 1); memcpy(extensions->san.uri, p, tmpLen); } else if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 1)) { p++; tmpLen = *p++; if (extEnd - p < tmpLen) { return -1; } extensions->san.email = psMalloc(pool, tmpLen + 1); if (extensions->san.email == NULL) { return -8; /* SSL_MEM_ERROR */ } memset(extensions->san.email, 0x0, tmpLen + 1); memcpy(extensions->san.email, p, tmpLen); } else { matrixStrDebugMsg("Unsupported subjectAltName type.n", NULL); p++; tmpLen = *p++; if (extEnd - p < tmpLen) { return -1; } } p = p + tmpLen; len -= tmpLen + 2; /* the magic 2 is the type and length */ } break; #ifdef USE_FULL_CERT_PARSE case EXT_AUTH_KEY_ID: /* AuthorityKeyIdentifier ::= SEQUENCE { keyIdentifier [0] KeyIdentifier OPTIONAL, authorityCertIssuer [1] GeneralNames OPTIONAL, authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } KeyIdentifier ::= OCTET STRING */ if (getSequence(&p, (int32)(extEnd - p), &len) < 0) { return -1; } /* Have seen a cert that has a zero length ext here. Let it pass. */ if (len == 0) { break; } /* All memebers are optional */ if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 0)) { p++; if (asnParseLength(&p, (int32)(extEnd - p), &extensions->ak.keyLen) < 0 || extEnd - p < extensions->ak.keyLen) { return -1; } extensions->ak.keyId = psMalloc(pool, extensions->ak.keyLen); if (extensions->ak.keyId == NULL) { return -8; /* SSL_MEM_ERROR */ } memcpy(extensions->ak.keyId, p, extensions->ak.keyLen); p = p + extensions->ak.keyLen; } if (*p == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) { p++; if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || len < 1 || extEnd - p < len) { return -1; } if ((*p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED) != 4) { /* FUTURE: support other name types We are just dealing with DN formats here */ matrixIntDebugMsg("Error auth key-id name type: %d\n", *p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED); return -1; } p++; if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || extEnd - p < len) { return -1; } if (getDNAttributes(pool, &p, (int32)(extEnd - p), &(extensions->ak.attribs)) < 0) { return -1; } } if ((*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) || (*p == ASN_INTEGER)){ /* Treat as a serial number (not a native INTEGER) */ if (getSerialNum(pool, &p, (int32)(extEnd - p), &(extensions->ak.serialNum), &len) < 0) { return -1; } extensions->ak.serialNumLen = len; } break; case EXT_KEY_USAGE: /* KeyUsage ::= BIT STRING { digitalSignature (0), nonRepudiation (1), keyEncipherment (2), dataEncipherment (3), keyAgreement (4), keyCertSign (5), cRLSign (6), encipherOnly (7), decipherOnly (8) } */ if (*p++ != ASN_BIT_STRING) { return -1; } if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || extEnd - p < len) { return -1; } if (len != 2) { return -1; } /* Assure all unused bits are 0 and store away */ extensions->keyUsage = (*(p + 1)) & ~((1 << *p) -1); p = p + len; break; case EXT_SUBJ_KEY_ID: /* The value of the subject key identifier MUST be the value placed in the key identifier field of the Auth Key Identifier extension of certificates issued by the subject of this certificate. */ if (*p++ != ASN_OCTET_STRING || asnParseLength(&p, (int32)(extEnd - p), &(extensions->sk.len)) < 0 || extEnd - p < extensions->sk.len) { return -1; } extensions->sk.id = psMalloc(pool, extensions->sk.len); if (extensions->sk.id == NULL) { return -8; /* SSL_MEM_ERROR */ } memcpy(extensions->sk.id, p, extensions->sk.len); p = p + extensions->sk.len; break; #endif /* USE_FULL_CERT_PARSE */ /* Unsupported or skipping because USE_FULL_CERT_PARSE is undefined */ default: if (critical) { /* SPEC DIFFERENCE: Ignoring an unrecognized critical extension. The specification dictates an error should occur, but real-world experience has shown this is not a realistic or desirable action. Also, no other SSL implementations have been found to error in this case. It is NOT a security risk in an RSA authenticaion sense. */ matrixStrDebugMsg("Unknown critical ext encountered\n", NULL); } p++; /* Skip over based on the length reported from the ASN_SEQUENCE surrounding the entire extension. It is not a guarantee that the value of the extension itself will contain it's own length. */ p = p + (fullExtLen - (p - extStart)); break; } } *pp = p; return 0; }
/* 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, int32 secretLen) { sslMd5Context_t md5Ctx; sslSha1Context_t sha1Ctx; unsigned char buf[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE]; unsigned char *tmp; int32 keyIter, i, ret = 0; int32 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 (SSL_MD5_HASH_SIZE * keyIter < reqKeyLen) { keyIter++; } if (keyIter > sizeof(salt)/sizeof(char*)) { matrixIntDebugMsg("Error: Not enough salt for key length of %d\n", reqKeyLen); return -1; } tmp = ssl->sec.keyBlock; for (i = 0; i < keyIter; i++) { matrixSha1Init(&sha1Ctx); matrixSha1Update(&sha1Ctx, salt[i], i + 1); matrixSha1Update(&sha1Ctx, masterSecret, secretLen); matrixSha1Update(&sha1Ctx, serverRandom, SSL_HS_RANDOM_SIZE); matrixSha1Update(&sha1Ctx, clientRandom, SSL_HS_RANDOM_SIZE); matrixSha1Final(&sha1Ctx, buf); matrixMd5Init(&md5Ctx); matrixMd5Update(&md5Ctx, masterSecret, secretLen); matrixMd5Update(&md5Ctx, buf, SSL_SHA1_HASH_SIZE); matrixMd5Final(&md5Ctx, tmp); tmp += SSL_MD5_HASH_SIZE; ret += SSL_MD5_HASH_SIZE; } memset(buf, 0x0, SSL_MD5_HASH_SIZE + SSL_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; }