summaryrefslogtreecommitdiff
path: root/release/src/router/matrixssl/src/crypto/peersec/rsa.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 13:58:15 +0100
commit4aca87515a5083ae0e31ce3177189fd43b6d05ac (patch)
tree7b1d9a31393ca090757dc6f0d3859b4fcd93f271 /release/src/router/matrixssl/src/crypto/peersec/rsa.c
parent008d0be72b2f160382c6e880765e96b64a050c65 (diff)
downloadtomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.gz
tomato-4aca87515a5083ae0e31ce3177189fd43b6d05ac.tar.bz2
patch to Vanilla Tomato 1.28
Diffstat (limited to 'release/src/router/matrixssl/src/crypto/peersec/rsa.c')
-rw-r--r--release/src/router/matrixssl/src/crypto/peersec/rsa.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/release/src/router/matrixssl/src/crypto/peersec/rsa.c b/release/src/router/matrixssl/src/crypto/peersec/rsa.c
new file mode 100644
index 00000000..5d6fcccb
--- /dev/null
+++ b/release/src/router/matrixssl/src/crypto/peersec/rsa.c
@@ -0,0 +1,463 @@
+/*
+ * rsa.c
+ * Release $Name: MATRIXSSL_1_8_8_OPEN $
+ *
+ * RSA crypto
+ */
+/*
+ * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
+ * The latest version of this code is available at http://www.matrixssl.org
+ *
+ * This software is open source; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This General Public License does NOT permit incorporating this software
+ * into proprietary programs. If you are unable to comply with the GPL, a
+ * commercial license for this software may be purchased from PeerSec Networks
+ * at http://www.peersec.com
+ *
+ * This program is distributed in WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+/******************************************************************************/
+
+#include "../cryptoLayer.h"
+
+/******************************************************************************/
+
+static int32 ssl_rsa_crypt(psPool_t *pool,
+ const unsigned char *in, uint32 inlen,
+ unsigned char *out, uint32 *outlen,
+ sslRsaKey_t *key, int32 type);
+
+static int32 sslUnpadRSA(unsigned char *in, int32 inlen, unsigned char *out,
+ int32 outlen, int32 decryptType);
+static int32 sslPadRSA(unsigned char *in, int32 inlen, unsigned char *out,
+ int32 outlen, int32 cryptType);
+
+#ifdef USE_RSA_BLINDING
+static int32 tim_mp_exptmod(psPool_t *pool,
+ mp_int *c, mp_int *e, mp_int *d, mp_int *n, mp_int *m);
+#else
+#define tim_mp_exptmod(p, c, e, d, n, m) mp_exptmod(p, c, d, n, m)
+#endif
+
+/******************************************************************************/
+
+#define RSA_PUBLIC 0x01
+#define RSA_PRIVATE 0x02
+
+/******************************************************************************/
+/*
+ Public API wrapper around sslGetEntropy
+*/
+int32 matrixGetRandomBytes(unsigned char *bytes, int32 size)
+{
+ return sslGetEntropy(bytes, size);
+}
+
+/******************************************************************************/
+/*
+ Primary RSA encryption routine
+*/
+static int32 ssl_rsa_crypt(psPool_t *pool,
+ const unsigned char *in, uint32 inlen,
+ unsigned char *out, uint32 *outlen,
+ sslRsaKey_t *key, int32 type)
+{
+ mp_int tmp, tmpa, tmpb;
+ unsigned long x;
+ int32 res;
+
+ if (in == NULL || out == NULL || outlen == NULL || key == NULL) {
+ return -1;
+ }
+/*
+ init and copy into tmp
+ */
+ if (_mp_init_multi(pool, &tmp, &tmpa, &tmpb, NULL, NULL, NULL, NULL, NULL)
+ != MP_OKAY) {
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_init_multi\n", NULL);
+ goto error;
+ }
+ if (mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int32)inlen) !=
+ MP_OKAY) {
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_read_unsigned_bin\n", NULL);
+ goto error;
+ }
+/*
+ sanity check on the input
+ */
+ if (mp_cmp(&key->N, &tmp) == MP_LT) {
+ res = -1;
+ goto done;
+ }
+ if (type == RSA_PRIVATE) {
+ if (key->optimized) {
+ if (tim_mp_exptmod(pool, &tmp, &key->e, &key->dP, &key->p, &tmpa)
+ != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: mp_exptmod dP, p\n", NULL);
+ goto error;
+ }
+ if (tim_mp_exptmod(pool, &tmp, &key->e, &key->dQ, &key->q, &tmpb)
+ != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: mp_exptmod dQ, q\n", NULL);
+ goto error;
+ }
+ if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: sub tmpb, tmp\n", NULL);
+ goto error;
+ }
+ if (mp_mulmod(pool, &tmp, &key->qP, &key->p, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: mp_mulmod qP, p\n", NULL);
+ goto error;
+ }
+ if (mp_mul(pool, &tmp, &key->q, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: mp_mul q \n", NULL);
+ goto error;
+ }
+ if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("decrypt error: mp_add tmp \n", NULL);
+ goto error;
+ }
+ } else {
+ if (tim_mp_exptmod(pool, &tmp, &key->e, &key->d, &key->N, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_exptmod\n", NULL);
+ goto error;
+ }
+ }
+ } else if (type == RSA_PUBLIC) {
+ if (mp_exptmod(pool, &tmp, &key->e, &key->N, &tmp) != MP_OKAY) {
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_exptmod\n", NULL);
+ goto error;
+ }
+ } else {
+ matrixStrDebugMsg("ssl_rsa_crypt error: invalid type param\n", NULL);
+ goto error;
+ }
+/*
+ read it back
+ */
+ x = (unsigned long)mp_unsigned_bin_size(&key->N);
+ if (x > *outlen) {
+ res = -1;
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_unsigned_bin_size\n", NULL);
+ goto done;
+ }
+/*
+ We want the encrypted value to always be the key size. Pad with 0x0
+*/
+ while (x < (unsigned long)key->size) {
+ *out++ = 0x0;
+ x++;
+ }
+
+ *outlen = x;
+/*
+ convert it
+ */
+ memset(out, 0x0, x);
+ if (mp_to_unsigned_bin(pool, &tmp, out+(x-mp_unsigned_bin_size(&tmp)))
+ != MP_OKAY) {
+ matrixStrDebugMsg("ssl_rsa_crypt error: mp_to_unsigned_bin\n", NULL);
+ goto error;
+ }
+/*
+ clean up and return
+ */
+ res = 0;
+ goto done;
+error:
+ res = -1;
+done:
+ _mp_clear_multi(&tmp, &tmpa, &tmpb, NULL, NULL, NULL, NULL, NULL);
+ return res;
+}
+
+/******************************************************************************/
+/*
+ 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;
+}
+
+
+#ifdef USE_RSA_PUBLIC_ENCRYPT
+/******************************************************************************/
+/*
+ RSA public encryption.
+ Always called by SSL client for server auth in ClientKeyExchange
+ The outlen param must be set to the strength of the key: key->size
+*/
+int32 matrixRsaEncryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ int32 size;
+
+ size = key->size;
+ if (outlen < size) {
+ return -1;
+ }
+
+ if (sslPadRSA(in, inlen, out, size, RSA_PRIVATE) < 0) {
+ return -1;
+ }
+ if (ssl_rsa_crypt(pool, out, size, out, (uint32*)&outlen, key,
+ RSA_PUBLIC) < 0 || outlen != size) {
+ return -1;
+ }
+ return size;
+}
+
+#else /* USE_RSA_PUBLIC_ENCRYPT - Keeps the cipher suite definition clean */
+int32 matrixRsaEncryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ if (inlen > outlen) {
+ return -1;
+ }
+ memcpy(out, in, inlen);
+ return inlen;
+}
+#endif /* USE_RSA_PUBLIC_ENCRYPT */
+
+/******************************************************************************/
+/*
+ Unpad a value decrypted by RSA, according to PKCS#1 v1.5
+ http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/
+
+ When decrypted, the data will look like the pad, including the inital
+ byte (00). Form:
+ 00 <decryptType> <random data (min 8 bytes)> 00 <value to be encrypted>
+
+ We don't worry about v2 rollback issues because we don't support v2
+*/
+static int32 sslUnpadRSA(unsigned char *in, int32 inlen, unsigned char *out,
+ int32 outlen, int32 decryptType)
+{
+ unsigned char *c, *end;
+
+ if (inlen < outlen + 10) {
+ return -1;
+ }
+ c = in;
+ end = in + inlen;
+/*
+ Verify the first byte (block type) is correct.
+*/
+ if (*c++ != 0x00 || *c != decryptType) {
+ return -1;
+ }
+ c++;
+/*
+ Skip over the random, non-zero bytes used as padding
+*/
+ while (c < end && *c != 0x0) {
+ if (decryptType == RSA_PUBLIC) {
+ if (*c != 0xFF) {
+ return -1;
+ }
+ }
+ c++;
+ }
+ c++;
+/*
+ The length of the remaining data should be equal to what was expected
+ Combined with the initial length check, there must be >= 8 bytes of pad
+ ftp://ftp.rsa.com/pub/pdfs/bulletn7.pdf
+*/
+ if (end - c != outlen) {
+ return -1;
+ }
+/*
+ Copy the value bytes to the out buffer
+*/
+ while (c < end) {
+ *out = *c;
+ out++; c++;
+ }
+ return outlen;
+}
+
+/******************************************************************************/
+/*
+ Always called by the server to decrypt the ClientKeyExchange
+*/
+int32 matrixRsaDecryptPriv(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ int32 ptLen;
+
+ if (inlen != key->size) {
+ return -1;
+ }
+ ptLen = inlen;
+ if (ssl_rsa_crypt(pool, in, inlen, in, (uint32*)&ptLen, key,
+ RSA_PRIVATE) < 0 || ptLen != inlen) {
+ return -1;
+ }
+ ptLen = sslUnpadRSA(in, inlen, out, outlen, RSA_PRIVATE);
+ memset(in, 0x0, inlen);
+ return ptLen;
+}
+
+/******************************************************************************/
+/*
+ Called by client as normal part of signature validation from server cert.
+ Called by the server if authenticating client in CertificateVerify
+*/
+int32 matrixRsaDecryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ int32 ptLen;
+
+ if (inlen != key->size) {
+ return -1;
+ }
+ ptLen = inlen;
+ if (ssl_rsa_crypt(pool, in, inlen, in, (uint32*)&ptLen, key,
+ RSA_PUBLIC) < 0 || ptLen != inlen) {
+ return -1;
+ }
+ if ((ptLen = sslUnpadRSA(in, inlen, out, outlen, RSA_PUBLIC)) < 0) {
+ return ptLen;
+ }
+ return 0;
+}
+
+
+#ifdef USE_RSA_BLINDING
+
+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;
+}
+#endif /* USE_RSA_BLINDING */
+
+/******************************************************************************/
+
+
+
+
+