/* Pad a value to be encrypted by RSA, according to PKCS#1 v1.5 http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ When encrypting a value with RSA, the value is first padded to be equal to the public key size using the following method: 00 <id> <data> 00 <value to be encrypted> - id denotes a public or private key operation - if id is private, data is however many non-zero bytes it takes to pad the value to the key length (randomLen = keyLen - 3 - valueLen). - if id is public, data is FF for the same length as described above - There must be at least 8 bytes of data. */ static int32 sslPadRSA(unsigned char *in, int32 inlen, unsigned char *out, int32 outlen, int32 cryptType) { unsigned char *c; int32 randomLen; randomLen = outlen - 3 - inlen; if (randomLen < 8) { matrixIntDebugMsg("RSA encryption data too large: %d\n", inlen); return -1; } c = out; *c = 0x00; c++; *c = (unsigned char)cryptType; c++; if (cryptType == RSA_PUBLIC) { while (randomLen-- > 0) { *c++ = 0xFF; } } else { if (sslGetEntropy(c, randomLen) < 0) { matrixStrDebugMsg("Error gathering RSA pad entropy\n", NULL); return -1; } /* SECURITY: Read through the random data and change all 0x0 to 0x01. This is per spec that no random bytes should be 0 */ while (randomLen-- > 0) { if (*c == 0x0) { *c = 0x01; } c++; } } *c = 0x00; c++; memcpy(c, in, inlen); return outlen; }
/* Write out the ServerHello message */ static int32 writeServerHello(ssl_t *ssl, sslBuf_t *out) { unsigned char *c, *end, *encryptStart; char padLen; int32 messageSize, rc; time_t t; c = out->end; end = out->buf + out->size; /* Calculate the size of the message up front, and verify we have room We assume there will be a sessionId in the message, and make adjustments below if there is no sessionId. */ messageSize = ssl->recordHeadLen + ssl->hshakeHeadLen + 38 + SSL_MAX_SESSION_ID_SIZE; /* First 4 bytes of the serverRandom are the unix time to prevent replay attacks, the rest are random */ t = time(0); ssl->sec.serverRandom[0] = (unsigned char)((t & 0xFF000000) >> 24); ssl->sec.serverRandom[1] = (unsigned char)((t & 0xFF0000) >> 16); ssl->sec.serverRandom[2] = (unsigned char)((t & 0xFF00) >> 8); ssl->sec.serverRandom[3] = (unsigned char)(t & 0xFF); if (sslGetEntropy(ssl->sec.serverRandom + 4, SSL_HS_RANDOM_SIZE - 4) < 0) { matrixStrDebugMsg("Error gathering serverRandom entropy\n", NULL); return SSL_ERROR; } /* We register session here because at this point the serverRandom value is populated. If we are able to register the session, the sessionID and sessionIdLen fields will be non-NULL, otherwise the session couldn't be registered. */ if (!(ssl->flags & SSL_FLAGS_RESUMED)) { matrixRegisterSession(ssl); } messageSize -= (SSL_MAX_SESSION_ID_SIZE - ssl->sessionIdLen); if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE, SSL_HS_SERVER_HELLO, &messageSize, &padLen, &encryptStart, &end, &c)) < 0) { return rc; } /* First two fields in the ServerHello message are the major and minor SSL protocol versions we agree to talk with */ *c = ssl->majVer; c++; *c = ssl->minVer; c++; /* The next 32 bytes are the server's random value, to be combined with the client random and premaster for key generation later */ memcpy(c, ssl->sec.serverRandom, SSL_HS_RANDOM_SIZE); c += SSL_HS_RANDOM_SIZE; /* The next data is a single byte containing the session ID length, and up to 32 bytes containing the session id. First register the session, which will give us a session id and length if not all session slots in the table are used */ *c = ssl->sessionIdLen; c++; if (ssl->sessionIdLen > 0) { memcpy(c, ssl->sessionId, ssl->sessionIdLen); c += ssl->sessionIdLen; } /* Two byte cipher suite we've chosen based on the list sent by the client and what we support. One byte compression method (always zero) */ *c = (ssl->cipher->id & 0xFF00) >> 8; c++; *c = ssl->cipher->id & 0xFF; c++; *c = 0; c++; if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize, padLen, encryptStart, out, &c)) < 0) { return rc; } /* If we're resuming a session, we now have the clientRandom, master and serverRandom, so we can derive keys which we'll be using shortly. */ if (ssl->flags & SSL_FLAGS_RESUMED) { sslDeriveKeys(ssl); } /* Verify that we've calculated the messageSize correctly, really this should never fail; it's more of an implementation verification */ if (c - out->end != messageSize) { return SSL_ERROR; } out->end = c; return SSL_SUCCESS; }
/* Public API wrapper around sslGetEntropy */ int32 matrixGetRandomBytes(unsigned char *bytes, int32 size) { return sslGetEntropy(bytes, size); }
static int32 tim_mp_exptmod(psPool_t *pool, mp_int *c, mp_int *e, mp_int *d, mp_int *n, mp_int *m) { int32 err; mp_int r, tmp, tmp2; unsigned char *rtmp; unsigned long rlen; /* pick random r */ rlen = mp_unsigned_bin_size(n); rtmp = psMalloc(pool, rlen); if (rtmp == NULL) { return -8; /* SSL_MEM_ERROR */ } sslGetEntropy(rtmp, rlen); if ((err = _mp_init_multi(pool, &r, &tmp, &tmp2, NULL, NULL, NULL, NULL, NULL)) != MP_OKAY) { psFree(rtmp); return -1; } /* read in r */ if ((err = mp_read_unsigned_bin(&r, rtmp, rlen)) != MP_OKAY) { goto __ERR; } /* compute tmp = r^e */ if ((err = mp_exptmod(pool, &r, e, n, &tmp)) != MP_OKAY) { goto __ERR; } /* multiply C into the mix */ if ((err = mp_mulmod(pool, c, &tmp, n, &tmp)) != MP_OKAY) { goto __ERR; } /* raise to d */ if ((err = mp_exptmod(pool, &tmp, d, n, &tmp)) != MP_OKAY) { goto __ERR; } /* invert r and multiply */ if ((err = mp_invmod(pool, &r, n, &tmp2)) != MP_OKAY) { goto __ERR; } /* multiply and we are totally set */ if ((err = mp_mulmod(pool, &tmp, &tmp2, n, m)) != MP_OKAY) { goto __ERR; } __ERR: _mp_clear_multi(&r, &tmp, &tmp2, NULL, NULL, NULL, NULL, NULL); psFree(rtmp); return err; }