Example #1
0
int32  matrixSha1Test()
{
	static const struct {
		char *msg;
		unsigned char hash[20];
	} tests[] = {
		{ "abc",
		{ 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
			0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
			0x9c, 0xd0, 0xd8, 0x9d }
		},
		{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
		{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
			0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
			0xE5, 0x46, 0x70, 0xF1 }
		}
	};

	int32 i;
	unsigned char tmp[20];
	hash_state md;

	for (i = 0; i < (int32)(sizeof(tests) / sizeof(tests[0]));  i++) {
		matrixSha1Init(&md);
		matrixSha1Update(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
		matrixSha1Final(&md, tmp);
		if (memcmp(tmp, tests[i].hash, 20) != 0) {
			return CRYPT_FAIL_TESTVECTOR;
		}
	}
	return CRYPT_OK;
}
Example #2
0
/*
 *	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;
}
Example #3
0
/*
	SSLv3 uses a method similar to HMAC to generate the SHA1 message MAC.
	For SHA1, 40 bytes of the pad are used.

	SHA1(MAC_write_secret + pad2 + 
		SHA1(MAC_write_secret + pad1 + seq_num + length + content));
*/
int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq, 
						unsigned char type, unsigned char *data, int32 len,
						unsigned char *mac)
{
	sslSha1Context_t	sha1;
	unsigned char		ihash[SSL_SHA1_HASH_SIZE];
	int32				i;

	matrixSha1Init(&sha1);
	matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
	matrixSha1Update(&sha1, pad1, 40);
	matrixSha1Update(&sha1, seq, 8);
	ihash[0] = type;
	ihash[1] = (len & 0xFF00) >> 8;
	ihash[2] = len & 0xFF;
	matrixSha1Update(&sha1, ihash, 3);
	matrixSha1Update(&sha1, data, len);
	matrixSha1Final(&sha1, ihash);

	matrixSha1Init(&sha1);
	matrixSha1Update(&sha1, key, SSL_SHA1_HASH_SIZE);
	matrixSha1Update(&sha1, pad2, 40);
	matrixSha1Update(&sha1, ihash, SSL_SHA1_HASH_SIZE);
	matrixSha1Final(&sha1, mac);

/*
	Increment sequence number
*/
	for (i = 7; i >= 0; i--) {
		seq[i]++;
		if (seq[i] != 0) {
			break; 
		}
	}
	return SSL_SHA1_HASH_SIZE;
}
Example #4
0
/*
	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;
}
Example #5
0
/*
    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;
}
Example #6
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);
}
Example #7
0
/*
	Implementations of this specification MUST be prepared to receive
	the following standard attribute types in issuer names:
	country, organization, organizational-unit, distinguished name qualifier,
	state or province name, and common name 
*/
int32 getDNAttributes(psPool_t *pool, unsigned char **pp, int32 len, 
						   DNattributes_t *attribs)
{
	sslSha1Context_t	hash;
	unsigned char		*p = *pp;
	unsigned char		*dnEnd, *dnStart;
	int32				llen, setlen, arcLen, id, stringType;
	char				*stringOut;

	dnStart = p;
	if (getSequence(&p, len, &llen) < 0) {
		return -1;
	}
	dnEnd = p + llen;

	matrixSha1Init(&hash);
	while (p < dnEnd) {
		if (getSet(&p, (int32)(dnEnd - p), &setlen) < 0) {
			return -1;
		}
		if (getSequence(&p, (int32)(dnEnd - p), &llen) < 0) {
			return -1;
		}
		if (dnEnd <= p || (*(p++) != ASN_OID) ||
				asnParseLength(&p, (int32)(dnEnd - p), &arcLen) < 0 || 
				(dnEnd - p) < arcLen) {
			return -1;
		}
/*
		id-at   OBJECT IDENTIFIER       ::=     {joint-iso-ccitt(2) ds(5) 4}
		id-at-commonName		OBJECT IDENTIFIER		::=		{id-at 3}
		id-at-countryName		OBJECT IDENTIFIER		::=		{id-at 6}
		id-at-localityName		OBJECT IDENTIFIER		::=		{id-at 7}
		id-at-stateOrProvinceName		OBJECT IDENTIFIER	::=	{id-at 8}
		id-at-organizationName			OBJECT IDENTIFIER	::=	{id-at 10}
		id-at-organizationalUnitName	OBJECT IDENTIFIER	::=	{id-at 11}
*/
		*pp = p;
/*
		FUTURE: Currently skipping OIDs not of type {joint-iso-ccitt(2) ds(5) 4}
		However, we could be dealing with an OID we MUST support per RFC.
		domainComponent is one such example.
*/
		if (dnEnd - p < 2) {
			return -1;
		}
		if ((*p++ != 85) || (*p++ != 4) ) {
			p = *pp;
/*
			Move past the OID and string type, get data size, and skip it.
			NOTE: Have had problems parsing older certs in this area.
*/
			if (dnEnd - p < arcLen + 1) {
				return -1;
			}
			p += arcLen + 1;
			if (asnParseLength(&p, (int32)(dnEnd - p), &llen) < 0 || 
					dnEnd - p < llen) {
				return -1;
			}
			p = p + llen;
			continue;
		}
/*
		Next are the id of the attribute type and the ASN string type
*/
		if (arcLen != 3 || dnEnd - p < 2) {
			return -1;
		}
		id = (int32)*p++;
/*
		Done with OID parsing
*/
		stringType = (int32)*p++;

		asnParseLength(&p, (int32)(dnEnd - p), &llen);
		if (dnEnd - p < llen) {
			return -1;
		}
		switch (stringType) {
			case ASN_PRINTABLESTRING:
			case ASN_UTF8STRING:
			case ASN_IA5STRING:
			case ASN_T61STRING:
			case ASN_BMPSTRING:
				stringOut = psMalloc(pool, llen + 1);
				if (stringOut == NULL) {
					return -8; /* SSL_MEM_ERROR */
				}
				memcpy(stringOut, p, llen);
				stringOut[llen] = '\0';
				p = p + llen;
				break;
			default:
				matrixStrDebugMsg("Parsing untested DN attrib type\n", NULL);
				return -1;
		}

		switch (id) {
			case ATTRIB_COUNTRY_NAME:
				if (attribs->country) {
					psFree(attribs->country);
				}
				attribs->country = stringOut;
				break;
			case ATTRIB_STATE_PROVINCE:
				if (attribs->state) {
					psFree(attribs->state);
				}
				attribs->state = stringOut;
				break;
			case ATTRIB_LOCALITY:
				if (attribs->locality) {
					psFree(attribs->locality);
				}
				attribs->locality = stringOut;
				break;
			case ATTRIB_ORGANIZATION:
				if (attribs->organization) {
					psFree(attribs->organization);
				}
				attribs->organization = stringOut;
				break;
			case ATTRIB_ORG_UNIT:
				if (attribs->orgUnit) {
					psFree(attribs->orgUnit);
				}
				attribs->orgUnit = stringOut;
				break;
			case ATTRIB_COMMON_NAME:
				if (attribs->commonName) {
					psFree(attribs->commonName);
				}
				attribs->commonName = stringOut;
				break;
/*
			Not a MUST support
*/
			default:
				psFree(stringOut);
				stringOut = NULL;
				break;
		}
/*
		Hash up the DN.  Nice for validation later
*/
		if (stringOut != NULL) {
			matrixSha1Update(&hash, (unsigned char*)stringOut, llen);
		}
	}
	matrixSha1Final(&hash, (unsigned char*)attribs->hash);
	*pp = p;
	return 0;
}
Example #8
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;
}