aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/matrixssl/src
diff options
context:
space:
mode:
authorqrort <qrort@yandex-team.com>2022-11-30 23:47:12 +0300
committerqrort <qrort@yandex-team.com>2022-11-30 23:47:12 +0300
commit22f8ae0e3f5d68b92aecccdf96c1d841a0334311 (patch)
treebffa27765faf54126ad44bcafa89fadecb7a73d7 /contrib/libs/matrixssl/src
parent332b99e2173f0425444abb759eebcb2fafaa9209 (diff)
downloadydb-22f8ae0e3f5d68b92aecccdf96c1d841a0334311.tar.gz
validate canons without yatest_common
Diffstat (limited to 'contrib/libs/matrixssl/src')
-rw-r--r--contrib/libs/matrixssl/src/cipherSuite.c441
-rw-r--r--contrib/libs/matrixssl/src/crypto/cryptoLayer.h154
-rw-r--r--contrib/libs/matrixssl/src/crypto/matrixCrypto.h145
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/arc4.c109
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/base64.c116
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/des3.c794
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/md2.c221
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/md5.c401
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/mpi.c3667
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/mpi.h476
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/pscrypto.h586
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/rsa.c463
-rw-r--r--contrib/libs/matrixssl/src/crypto/peersec/sha1.c317
-rw-r--r--contrib/libs/matrixssl/src/matrixConfig.h97
-rw-r--r--contrib/libs/matrixssl/src/matrixInternal.h396
-rw-r--r--contrib/libs/matrixssl/src/matrixSsl.c803
-rw-r--r--contrib/libs/matrixssl/src/os/debug.c62
-rw-r--r--contrib/libs/matrixssl/src/os/osLayer.h110
-rw-r--r--contrib/libs/matrixssl/src/os/psMalloc.h60
-rw-r--r--contrib/libs/matrixssl/src/os/yandex/yandex.cpp68
-rw-r--r--contrib/libs/matrixssl/src/pki/asn1.c454
-rw-r--r--contrib/libs/matrixssl/src/pki/matrixPki.h137
-rw-r--r--contrib/libs/matrixssl/src/pki/pkiInternal.h239
-rw-r--r--contrib/libs/matrixssl/src/pki/rsaPki.c681
-rw-r--r--contrib/libs/matrixssl/src/pki/x509.c1696
-rw-r--r--contrib/libs/matrixssl/src/sslDecode.c1387
-rw-r--r--contrib/libs/matrixssl/src/sslEncode.c1255
-rw-r--r--contrib/libs/matrixssl/src/sslv3.c375
-rw-r--r--contrib/libs/matrixssl/src/yandex.c9
29 files changed, 15719 insertions, 0 deletions
diff --git a/contrib/libs/matrixssl/src/cipherSuite.c b/contrib/libs/matrixssl/src/cipherSuite.c
new file mode 100644
index 00000000000..f24f7f6fc03
--- /dev/null
+++ b/contrib/libs/matrixssl/src/cipherSuite.c
@@ -0,0 +1,441 @@
+/*
+ * cipherSuite.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Wrappers for the various cipher suites.
+ * Contributors should add additional cipher suites here.
+ * Enable specific suites at compile time in matrixConfig.h
+ */
+/*
+ * 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 "matrixInternal.h"
+
+/******************************************************************************/
+/*
+ Using void *ssl rather than ssl_t *ssl is a workaround for a chicken-egg
+ issue in matrixInternal.h where these function prototypes are used
+ before ssl_t is defined.
+*/
+#ifdef USE_SHA1_MAC
+static int32 sha1GenerateMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+static int32 sha1VerifyMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+#endif
+
+#ifdef USE_MD5_MAC
+static int32 md5GenerateMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+static int32 md5VerifyMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+#endif
+
+#ifdef USE_SSL_RSA_WITH_RC4_128_MD5
+static int32 matrixCipher4Init(sslSec_t *sec, int32 type);
+#endif /* USE_SSL_RSA_WITH_RC4_128_MD5 */
+
+#ifdef USE_SSL_RSA_WITH_RC4_128_SHA
+static int32 matrixCipher5Init(sslSec_t *sec, int32 type);
+#endif /* USE_SSL_RSA_WITH_RC4_128_SHA */
+
+#ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+static int32 matrixCipherAInit(sslSec_t *sec, int32 type);
+#endif /* USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA */
+
+
+
+
+static int32 nullInit(sslSec_t *sec, int32 type);
+static int32 nullEncrypt(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+static int32 nullDecrypt(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+static int32 nullEncryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+static int32 nullDecryptPriv(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+static int32 nullGenerateMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+static int32 nullVerifyMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+
+/******************************************************************************/
+
+static sslCipherSpec_t supportedCiphers[] = {
+/*
+ New ciphers should be added here, similar to the ones below
+ These ciphers should be in order of the most desireable to the
+ least desireable ciphers to negotiate.
+*/
+#ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+ {SSL_RSA_WITH_3DES_EDE_CBC_SHA,
+ 20, /* macSize */
+ 24, /* keySize */
+ 8, /* ivSize */
+ 8, /* blocksize */
+ matrixCipherAInit,
+ matrix3desEncrypt,
+ matrix3desDecrypt,
+ NULL,
+ matrixRsaDecryptPub,
+ matrixRsaEncryptPub,
+ matrixRsaDecryptPriv,
+ sha1GenerateMac,
+ sha1VerifyMac},
+#endif /* USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA */
+#ifdef USE_SSL_RSA_WITH_RC4_128_SHA
+ {SSL_RSA_WITH_RC4_128_SHA,
+ 20, /* macSize */
+ 16, /* keySize */
+ 0, /* ivSize */
+ 1, /* blocksize */
+ matrixCipher5Init,
+ matrixArc4,
+ matrixArc4,
+ NULL,
+ matrixRsaDecryptPub,
+ matrixRsaEncryptPub,
+ matrixRsaDecryptPriv,
+ sha1GenerateMac,
+ sha1VerifyMac},
+#endif /* USE_SSL_RSA_WITH_RC4_128_SHA */
+#ifdef USE_SSL_RSA_WITH_RC4_128_MD5
+ {SSL_RSA_WITH_RC4_128_MD5,
+ 16, /* macSize */
+ 16, /* keySize */
+ 0, /* ivSize */
+ 1, /* blocksize */
+ matrixCipher4Init,
+ matrixArc4,
+ matrixArc4,
+ NULL,
+ matrixRsaDecryptPub,
+ matrixRsaEncryptPub,
+ matrixRsaDecryptPriv,
+ md5GenerateMac,
+ md5VerifyMac},
+#endif /* USE_SSL_RSA_WITH_RC4_128_MD5 */
+/*
+ These two USE_SSL_RSA_WITH_NULL ciphers are not recommended for use
+ in production applications.
+*/
+#ifdef USE_SSL_RSA_WITH_NULL_MD5
+ {SSL_RSA_WITH_NULL_MD5,
+ 16, /* macSize */
+ 0, /* keySize */
+ 0, /* ivSize */
+ 0, /* blocksize */
+ nullInit,
+ nullEncrypt,
+ nullDecrypt,
+ matrixRsaEncryptPriv,
+ matrixRsaDecryptPub,
+ matrixRsaEncryptPub,
+ matrixRsaDecryptPriv,
+ md5GenerateMac,
+ md5VerifyMac},
+#endif /* USE_SSL_RSA_WITH_NULL_MD5 */
+#ifdef USE_SSL_RSA_WITH_NULL_SHA
+ {SSL_RSA_WITH_NULL_SHA,
+ 20, /* macSize */
+ 0, /* keySize */
+ 0, /* ivSize */
+ 0, /* blocksize */
+ nullInit,
+ nullEncrypt,
+ nullDecrypt,
+ matrixRsaEncryptPriv,
+ matrixRsaDecryptPub,
+ matrixRsaEncryptPub,
+ matrixRsaDecryptPriv,
+ sha1GenerateMac,
+ sha1VerifyMac},
+#endif /* USE_SSL_RSA_WITH_NULL_SHA */
+/*
+ The NULL Cipher suite must exist and be the last in this list
+*/
+ {SSL_NULL_WITH_NULL_NULL,
+ 0,
+ 0,
+ 0,
+ 0,
+ nullInit,
+ nullEncrypt,
+ nullDecrypt,
+ nullEncryptPub,
+ nullDecryptPriv,
+ nullEncryptPub,
+ nullDecryptPriv,
+ nullGenerateMac,
+ nullVerifyMac}
+};
+
+/******************************************************************************/
+/*
+ Lookup the given cipher spec ID and return a pointer to the structure
+ if found. This is used when negotiating security, to find out what suites
+ we support.
+*/
+sslCipherSpec_t *sslGetCipherSpec(int32 id)
+{
+ int32 i;
+
+ i = 0;
+ do {
+ if ((int32)supportedCiphers[i].id == id) {
+ return &supportedCiphers[i];
+ }
+ } while (supportedCiphers[i++].id != SSL_NULL_WITH_NULL_NULL) ;
+
+ return NULL;
+}
+
+/******************************************************************************/
+/*
+ Write out a list of the supported cipher suites to the caller's buffer
+ First 2 bytes are the number of cipher suite bytes, the remaining bytes are
+ the cipher suites, as two byte, network byte order values.
+*/
+int32 sslGetCipherSpecList(unsigned char *c, int32 len)
+{
+ unsigned char *end, *p;
+ unsigned short i;
+
+ if (len < 4) {
+ return -1;
+ }
+ end = c + len;
+ p = c; c += 2;
+ for (i = 0; supportedCiphers[i].id != SSL_NULL_WITH_NULL_NULL; i++) {
+ if (end - c < 2) {
+ return -1;
+ }
+ *c = (unsigned char)((supportedCiphers[i].id & 0xFF00) >> 8); c++;
+ *c = (unsigned char)(supportedCiphers[i].id & 0xFF); c++;
+ }
+ i *= 2;
+ *p = (unsigned char)(i >> 8); p++;
+ *p = (unsigned char)(i & 0xFF);
+ return i + 2;
+}
+
+/******************************************************************************/
+/*
+ Return the length of the cipher spec list, including initial length bytes
+*/
+int32 sslGetCipherSpecListLen(void)
+{
+ int32 i;
+
+ for (i = 0; supportedCiphers[i].id != SSL_NULL_WITH_NULL_NULL; i++) {
+ }
+ return (i * 2) + 2;
+}
+
+
+/******************************************************************************/
+/*
+*/
+#ifdef USE_SHA1_MAC
+static int32 sha1GenerateMac(void *sslv, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ ssl_t *ssl = (ssl_t*)sslv;
+ return ssl3HMACSha1(ssl->sec.writeMAC, ssl->sec.seq, type, data, len, mac);
+}
+
+static int32 sha1VerifyMac(void *sslv, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ ssl_t *ssl = (ssl_t*)sslv;
+ unsigned char buf[SSL_SHA1_HASH_SIZE];
+
+ ssl3HMACSha1(ssl->sec.readMAC, ssl->sec.remSeq, type, data, len, buf);
+ if (memcmp(buf, mac, SSL_SHA1_HASH_SIZE) == 0) {
+ return 0;
+ }
+ return -1;
+}
+#endif /* USE_SHA1_MAC */
+
+/******************************************************************************/
+/*
+*/
+#ifdef USE_MD5_MAC
+static int32 md5GenerateMac(void *sslv, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ ssl_t *ssl = (ssl_t*)sslv;
+ return ssl3HMACMd5(ssl->sec.writeMAC, ssl->sec.seq, type, data, len, mac);
+}
+
+static int32 md5VerifyMac(void *sslv, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ ssl_t *ssl = (ssl_t*)sslv;
+ unsigned char buf[SSL_MD5_HASH_SIZE];
+
+ ssl3HMACMd5(ssl->sec.readMAC, ssl->sec.remSeq, type, data, len, buf);
+ if (memcmp(buf, mac, SSL_MD5_HASH_SIZE) == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+#endif /* USE_MD5_MAC */
+
+/******************************************************************************/
+/*
+ SSL_RSA_WITH_RC4_128_SHA cipher init
+*/
+#ifdef USE_SSL_RSA_WITH_RC4_128_MD5
+static int32 matrixCipher4Init(sslSec_t *sec, int32 type)
+{
+ if (type == INIT_ENCRYPT_CIPHER) {
+ matrixArc4Init(&(sec->encryptCtx), sec->writeKey, 16);
+ } else {
+ matrixArc4Init(&(sec->decryptCtx), sec->readKey, 16);
+ }
+
+ return 0;
+}
+#endif /* USE_SSL_RSA_WITH_RC4_128_MD5 */
+
+/******************************************************************************/
+/*
+ SSL_RSA_WITH_RC4_128_SHA cipher init
+*/
+#ifdef USE_SSL_RSA_WITH_RC4_128_SHA
+static int32 matrixCipher5Init(sslSec_t *sec, int32 type)
+{
+ if (type == INIT_ENCRYPT_CIPHER) {
+ matrixArc4Init(&(sec->encryptCtx), sec->writeKey, 16);
+ } else {
+ matrixArc4Init(&(sec->decryptCtx), sec->readKey, 16);
+ }
+
+ return 0;
+}
+#endif /* USE_SSL_RSA_WITH_RC4_128_SHA */
+
+/******************************************************************************/
+/*
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA cipher init
+*/
+#ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+static int32 matrixCipherAInit(sslSec_t *sec, int32 type)
+{
+ if (type == INIT_ENCRYPT_CIPHER) {
+ if (matrix3desInit(&(sec->encryptCtx), sec->writeIV, sec->writeKey,
+ SSL_DES3_KEY_LEN) < 0) {
+ return -1;
+ }
+ } else {
+ if (matrix3desInit(&(sec->decryptCtx), sec->readIV, sec->readKey,
+ SSL_DES3_KEY_LEN) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+#endif /* USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA */
+
+
+/******************************************************************************/
+/*
+ SSL_NULL_WITH_NULL_NULL cipher functions
+ Used in handshaking before SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC message
+ FUTURE - remove the memcpy to support in-situ decryption
+*/
+static int32 nullInit(sslSec_t *sec, int32 type)
+{
+ return 0;
+}
+
+static int32 nullEncrypt(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len)
+{
+ if (out != in) {
+ memcpy(out, in, len);
+ }
+ return len;
+}
+
+static int32 nullDecrypt(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len)
+{
+ if (out != in) {
+ memcpy(out, in, len);
+ }
+ return len;
+}
+
+/*
+ FUTURE - remove both apis below
+*/
+static int32 nullEncryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ if (inlen <= outlen) {
+ matrixStrDebugMsg("Error: output buffer too small for NULL encrypt\n",
+ NULL);
+ return -1;
+ }
+ memcpy(out, in, inlen);
+ return inlen;
+}
+
+static int32 nullDecryptPriv(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen)
+{
+ if (inlen <= outlen) {
+ matrixStrDebugMsg("Error: output buffer too small for NULL decrypt\n",
+ NULL);
+ return -1;
+ }
+ memcpy(out, in, inlen);
+ return inlen;
+}
+
+static int32 nullGenerateMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ return 0;
+}
+
+static int32 nullVerifyMac(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac)
+{
+ return 0;
+}
+
+
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/cryptoLayer.h b/contrib/libs/matrixssl/src/crypto/cryptoLayer.h
new file mode 100644
index 00000000000..62ffe5f43b1
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/cryptoLayer.h
@@ -0,0 +1,154 @@
+/*
+ * cryptoLayer.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Cryptography provider layered header. This layer decouples
+ * the cryptography implementation from the SSL protocol implementation.
+ * Contributors adding new providers must implement all functions
+ * externed below.
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_CRYPTO_LAYER
+#define _h_CRYPTO_LAYER
+#define _h_EXPORT_SYMBOLS
+
+/******************************************************************************/
+/*
+ Crypto may have some reliance on os layer (psMalloc in particular)
+*/
+#include "../os/osLayer.h"
+
+/*
+ Return the length of padding bytes required for a record of 'LEN' bytes
+ The name Pwr2 indicates that calculations will work with 'BLOCKSIZE'
+ that are powers of 2.
+ Because of the trailing pad length byte, a length that is a multiple
+ of the pad bytes
+*/
+#define sslPadLenPwr2(LEN, BLOCKSIZE) \
+ BLOCKSIZE <= 1 ? (unsigned char)0 : \
+ (unsigned char)(BLOCKSIZE - ((LEN) & (BLOCKSIZE - 1)))
+
+/*
+ Define the default crypto provider here
+*/
+#define USE_PEERSEC_CRYPTO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SSL_MD5_HASH_SIZE 16
+#define SSL_SHA1_HASH_SIZE 20
+
+#define SSL_MAX_MAC_SIZE 20
+#define SSL_MAX_IV_SIZE 16
+#define SSL_MAX_BLOCK_SIZE 16
+#define SSL_MAX_SYM_KEY_SIZE 32
+
+#define USE_X509 /* Must define for certificate support */
+/*
+ Enable the algorithms used for each cipher suite
+*/
+
+#ifdef USE_SSL_RSA_WITH_NULL_MD5
+#define USE_RSA
+#define USE_MD5_MAC
+#endif
+
+#ifdef USE_SSL_RSA_WITH_NULL_SHA
+#define USE_RSA
+#define USE_SHA1_MAC
+#endif
+
+#ifdef USE_SSL_RSA_WITH_RC4_128_SHA
+#define USE_ARC4
+#define USE_SHA1_MAC
+#define USE_RSA
+#endif
+
+#ifdef USE_SSL_RSA_WITH_RC4_128_MD5
+#define USE_ARC4
+#define USE_MD5_MAC
+#define USE_RSA
+#endif
+
+#ifdef USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+#define USE_3DES
+#define USE_SHA1_MAC
+#define USE_RSA
+#endif
+
+/*
+ Support for optionally encrypted private key files. These are
+ usually encrypted with 3DES.
+*/
+#ifdef USE_ENCRYPTED_PRIVATE_KEYS
+#define USE_3DES
+#endif
+
+/*
+ Support for client side SSL
+*/
+#ifdef USE_CLIENT_SIDE_SSL
+#define USE_RSA_PUBLIC_ENCRYPT
+#endif
+
+/*
+ Support for client authentication
+*/
+
+/*
+ Addtional crypt support
+*/
+#define USE_MD2
+
+/*
+ Now that we've set up the required defines, include the crypto provider
+*/
+#ifdef USE_PEERSEC_CRYPTO
+#include "peersec/pscrypto.h"
+#endif
+
+/******************************************************************************/
+/*
+ Include the public prototypes now. This level of indirection is needed
+ to properly expose the public APIs to DLLs. The circular reference
+ between these two files is avoided with the top level defines and the
+ order in which they are included is the key to making this work so edit
+ with caution.
+*/
+#include "matrixCrypto.h"
+
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* _h_CRYPTO_LAYER */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/matrixCrypto.h b/contrib/libs/matrixssl/src/crypto/matrixCrypto.h
new file mode 100644
index 00000000000..5cb105cd113
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/matrixCrypto.h
@@ -0,0 +1,145 @@
+/*
+ * matrixCrypto.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Public API set for matrixCrypto
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_MATRIX_CRYPTO
+#define _h_MATRIX_CRYPTO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "../../matrixCommon.h"
+
+/*
+ User application. Now include cryptoLayer to get the proper algorithm
+ defines so we know what API set to expose
+*/
+#include "cryptoLayer.h"
+
+/******************************************************************************/
+
+
+MATRIXPUBLIC int32 matrixGetRandomBytes(unsigned char *bytes, int32 size);
+
+#ifdef USE_ARC4
+MATRIXPUBLIC void matrixArc4Init(sslCipherContext_t *ctx, unsigned char *key,
+ int32 keylen);
+MATRIXPUBLIC int32 matrixArc4(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+#endif /* USE_ARC4 */
+
+#ifdef USE_3DES
+MATRIXPUBLIC int32 matrix3desInit(sslCipherContext_t *ctx, unsigned char *IV,
+ unsigned char *key, int32 keylen);
+MATRIXPUBLIC int32 matrix3desEncrypt(sslCipherContext_t *ctx, unsigned char *pt,
+ unsigned char *ct, int32 len);
+MATRIXPUBLIC int32 matrix3desDecrypt(sslCipherContext_t *ctx, unsigned char *ct,
+ unsigned char *pt, int32 len);
+MATRIXPUBLIC void generate3DESKey(unsigned char *pass, int32 passlen,
+ unsigned char *salt, unsigned char *key);
+#endif /* USE_3DES */
+
+
+
+/*
+ HMAC and message digests
+*/
+MATRIXPUBLIC int32 matrixHmacMd5(unsigned char *key, int32 keyLen,
+ const unsigned char *buf, unsigned long len,
+ unsigned char *hash, unsigned char *hmacKey,
+ int32 *hmacKeyLen);
+MATRIXPUBLIC void matrixHmacMd5Init(sslHmacContext_t *ctx,
+ unsigned char *key, int32 keyLen);
+MATRIXPUBLIC void matrixHmacMd5Update(sslHmacContext_t *ctx,
+ const unsigned char *buf, unsigned long len);
+MATRIXPUBLIC int32 matrixHmacMd5Final(sslHmacContext_t *ctx,
+ unsigned char *hash);
+
+MATRIXPUBLIC int32 matrixHmacSha1(unsigned char *key, int32 keyLen,
+ const unsigned char *buf, unsigned long len,
+ unsigned char *hash, unsigned char *hmacKey,
+ int32 *hmacKeyLen);
+MATRIXPUBLIC void matrixHmacSha1Init(sslHmacContext_t *ctx,
+ unsigned char *key, int32 keyLen);
+MATRIXPUBLIC void matrixHmacSha1Update(sslHmacContext_t *ctx,
+ const unsigned char *buf, unsigned long len);
+MATRIXPUBLIC int32 matrixHmacSha1Final(sslHmacContext_t *ctx,
+ unsigned char *hash);
+
+MATRIXPUBLIC void matrixSha1Init(sslSha1Context_t *ctx);
+MATRIXPUBLIC void matrixSha1Update(sslSha1Context_t *ctx,
+ const unsigned char *buf, unsigned long len);
+MATRIXPUBLIC int32 matrixSha1Final(sslSha1Context_t *ctx, unsigned char *hash);
+
+
+MATRIXPUBLIC void matrixMd5Init(sslMd5Context_t *ctx);
+MATRIXPUBLIC void matrixMd5Update(sslMd5Context_t *ctx,
+ const unsigned char *buf, unsigned long len);
+MATRIXPUBLIC int32 matrixMd5Final(sslMd5Context_t *ctx, unsigned char *hash);
+
+
+#ifdef USE_MD2
+/*
+ MD2 is provided for compatibility with V2 and older X509 certificates,
+ it is known to have security problems and should not be used for any current
+ development.
+*/
+MATRIXPUBLIC void matrixMd2Init(sslMd2Context_t *ctx);
+MATRIXPUBLIC int32 matrixMd2Update(sslMd2Context_t *ctx,
+ const unsigned char *buf, unsigned long len);
+MATRIXPUBLIC int32 matrixMd2Final(sslMd2Context_t *ctx, unsigned char *hash);
+#endif /* USE_MD2 */
+
+
+
+
+#ifdef USE_RSA
+MATRIXPUBLIC int32 matrixRsaEncryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+MATRIXPUBLIC int32 matrixRsaDecryptPriv(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+MATRIXPUBLIC int32 matrixRsaDecryptPub(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+#endif /* USE_RSA */
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MATRIX_CRYPTO */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/arc4.c b/contrib/libs/matrixssl/src/crypto/peersec/arc4.c
new file mode 100644
index 00000000000..c0e0757e380
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/arc4.c
@@ -0,0 +1,109 @@
+/*
+ * arc4.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * ARC4 stream cipher implementation
+ */
+/*
+ * 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"
+
+#ifdef USE_ARC4
+
+/*
+ Some accounts, such as O'Reilly's Secure Programming Cookbook say that no
+ more than 2^30 bytes should be processed without rekeying, so we
+ enforce that limit here. FYI, this is equal to 1GB of data transferred.
+*/
+#define ARC4_MAX_BYTES 0x40000000
+
+/******************************************************************************/
+/*
+ SSL_RSA_WITH_RC4_* cipher callbacks
+ */
+void matrixArc4Init(sslCipherContext_t *ctx, unsigned char *key, int32 keylen)
+{
+ unsigned char index1, index2, tmp, *state;
+ short counter;
+
+ ctx->arc4.byteCount = 0;
+ state = &ctx->arc4.state[0];
+
+ for (counter = 0; counter < 256; counter++) {
+ state[counter] = (unsigned char)counter;
+ }
+ ctx->arc4.x = 0;
+ ctx->arc4.y = 0;
+ index1 = 0;
+ index2 = 0;
+
+ for (counter = 0; counter < 256; counter++) {
+ index2 = (key[index1] + state[counter] + index2) & 0xff;
+
+ tmp = state[counter];
+ state[counter] = state[index2];
+ state[index2] = tmp;
+
+ index1 = (index1 + 1) % keylen;
+ }
+}
+
+int32 matrixArc4(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len)
+{
+ unsigned char x, y, *state, xorIndex, tmp;
+ short counter;
+
+ ctx->arc4.byteCount += len;
+ if (ctx->arc4.byteCount > ARC4_MAX_BYTES) {
+ return -1;
+ }
+
+ x = ctx->arc4.x;
+ y = ctx->arc4.y;
+ state = &ctx->arc4.state[0];
+ for (counter = 0; counter < len; counter++) {
+ x = (x + 1) & 0xff;
+ y = (state[x] + y) & 0xff;
+
+ tmp = state[x];
+ state[x] = state[y];
+ state[y] = tmp;
+
+ xorIndex = (state[x] + state[y]) & 0xff;
+
+ tmp = in[counter];
+ tmp ^= state[xorIndex];
+ out[counter] = tmp;
+ }
+ ctx->arc4.x = x;
+ ctx->arc4.y = y;
+ return len;
+}
+
+#endif /* USE_ARC4 */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/base64.c b/contrib/libs/matrixssl/src/crypto/peersec/base64.c
new file mode 100644
index 00000000000..572e1e39fad
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/base64.c
@@ -0,0 +1,116 @@
+/*
+ * base64.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Base64 operations
+ */
+/*
+ * 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 const unsigned char map[256] = {
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
+255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
+255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+255, 255, 255, 255 };
+
+int32 ps_base64_decode(const unsigned char *in, uint32 len,
+ unsigned char *out, uint32 *outlen)
+{
+ unsigned long t, x, y, z;
+ unsigned char c;
+ int32 g;
+
+ if (in == NULL || out == NULL || outlen == NULL) {
+ return -1;
+ }
+ g = 3;
+ for (x = y = z = t = 0; x < len; x++) {
+ c = map[in[x]&0xFF];
+ if (c == 255) {
+ continue;
+ }
+/*
+ the final = symbols are read and used to trim the remaining bytes
+ */
+ if (c == 254) {
+ c = 0;
+/*
+ prevent g < 0 which would potentially allow an overflow later
+ */
+ if (--g < 0) {
+ return CRYPT_INVALID_PACKET;
+ }
+ } else if (g != 3) {
+/*
+ we only allow = to be at the end
+ */
+ return CRYPT_INVALID_PACKET;
+ }
+
+ t = (t<<6)|c;
+
+ if (++y == 4) {
+ if (z + g > *outlen) {
+ return CRYPT_BUFFER_OVERFLOW;
+ }
+ out[z++] = (unsigned char)((t>>16)&255);
+ if (g > 1) {
+ out[z++] = (unsigned char)((t>>8)&255);
+ }
+ if (g > 2) {
+ out[z++] = (unsigned char)(t&255);
+ }
+ y = t = 0;
+ }
+ }
+ if (y != 0) {
+ return -1;
+ }
+ *outlen = z;
+ return 0;
+}
+
+/******************************************************************************/
+
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/des3.c b/contrib/libs/matrixssl/src/crypto/peersec/des3.c
new file mode 100644
index 00000000000..6683f6f247f
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/des3.c
@@ -0,0 +1,794 @@
+/*
+ * des3.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * 3DES block cipher implementation for low memory usage
+ */
+/*
+ * 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"
+
+#ifdef USE_3DES
+
+#define EN0 0
+#define DE1 1
+
+static const ulong32 bytebit[8] =
+{
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const ulong32 bigbyte[24] =
+{
+ 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL,
+ 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL,
+ 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
+ 0x800UL, 0x400UL, 0x200UL, 0x100UL,
+ 0x80UL, 0x40UL, 0x20UL, 0x10UL,
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
+};
+
+static const unsigned char pc1[56] = {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+};
+
+static const unsigned char pc2[48] = {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+};
+
+static const unsigned char totrot[16] = {
+ 1, 2, 4, 6,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
+ 23, 25, 27, 28
+};
+
+static const ulong32 SP1[] =
+{
+ 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+ 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+ 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+ 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+ 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+ 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+ 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+ 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+ 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+ 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+ 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+ 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+ 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+ 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const ulong32 SP2[] =
+{
+ 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+ 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+ 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+ 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+ 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+ 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+ 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+ 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+ 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+ 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+ 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+ 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+ 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+ 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+ 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+ 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const ulong32 SP3[] =
+{
+ 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+ 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+ 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+ 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+ 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+ 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+ 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+ 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+ 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+ 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+ 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+ 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+ 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+ 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const ulong32 SP4[] =
+{
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+ 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+ 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+ 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+ 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+ 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+ 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+ 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+ 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const ulong32 SP5[] =
+{
+ 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+ 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+ 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+ 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+ 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+ 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+ 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+ 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+ 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+ 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+ 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+ 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+ 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+ 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+ 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+ 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const ulong32 SP6[] =
+{
+ 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+ 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+ 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+ 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+ 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+ 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+ 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+ 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+ 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+ 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+ 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+ 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+ 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+ 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const ulong32 SP7[] =
+{
+ 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+ 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+ 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+ 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+ 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+ 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+ 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+ 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+ 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+ 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+ 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+ 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+ 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+ 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+ 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+ 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const ulong32 SP8[] =
+{
+ 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+ 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+ 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+ 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+ 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+ 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+ 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+ 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+ 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+ 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+ 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+ 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+ 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+ 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+ 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+ 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL,
+ 0xe1f27f3aUL, 0xf5710fb0UL, 0xada0e5c4UL, 0x98e4c919UL
+};
+
+static void cookey(const ulong32 *raw1, ulong32 *keyout);
+static void deskey(const unsigned char *key, short edf, ulong32 *keyout);
+
+/******************************************************************************/
+/*
+ Init the 3DES block cipher context for CBC-EDE mode.
+ IV should point to 8 bytes of initialization vector
+ Key should point to 24 bytes of data
+*/
+int32 matrix3desInit(sslCipherContext_t *ctx, unsigned char *IV,
+ unsigned char *key, int32 keylen)
+{
+ int32 x, err;
+
+ if (IV == NULL || key == NULL || ctx == NULL || keylen != SSL_DES3_KEY_LEN){
+ return -1;
+ }
+/*
+ setup cipher
+ */
+ if ((err = des3_setup(key, keylen, 0, &ctx->des3)) != CRYPT_OK) {
+ return -1;
+ }
+/*
+ copy IV
+ */
+ ctx->des3.blocklen = SSL_DES3_IV_LEN;
+ for (x = 0; x < ctx->des3.blocklen; x++) {
+ ctx->des3.IV[x] = IV[x];
+ }
+ ctx->des3.explicitIV = 0;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Encrypt a buffer using 3DES-EDE-CBC
+ (Encrypt Decrypt Encrypt and Cipher Block Chaining)
+ len must be a multiple of blockLen (8 bytes)
+*/
+int32 matrix3desEncrypt(sslCipherContext_t *ctx, unsigned char *pt,
+ unsigned char *ct, int32 len)
+{
+ int32 x, i;
+ unsigned char tmp[MAXBLOCKSIZE];
+
+ if (pt == NULL || ct == NULL || ctx == NULL || (len & 0x7) != 0) {
+ return -1;
+ }
+
+ /* is blocklen valid? */
+ if (ctx->des3.blocklen < 0 || ctx->des3.blocklen >
+ (int32)sizeof(ctx->des3.IV)) {
+ return -1;
+ }
+
+ for (i = 0; i < len; i += ctx->des3.blocklen) {
+ /* xor IV against plaintext */
+ for (x = 0; x < ctx->des3.blocklen; x++) {
+ tmp[x] = pt[x] ^ ctx->des3.IV[x];
+ }
+ /* encrypt */
+ des3_ecb_encrypt(tmp, (unsigned char*)ct, &ctx->des3);
+
+ /* store IV [ciphertext] for a future block */
+ for (x = 0; x < ctx->des3.blocklen; x++) {
+ ctx->des3.IV[x] = ct[x];
+ }
+ ct += ctx->des3.blocklen;
+ pt += ctx->des3.blocklen;
+ }
+
+#ifdef CLEAN_STACK
+ psZeromem(tmp, sizeof(tmp));
+#endif /* CLEAN STACK */
+ return len;
+}
+
+/******************************************************************************/
+/*
+ Decrypt a buffer using 3DES-EDE-CBC
+ (Encrypt Decrypt Encrypt and Cipher Block Chaining)
+ len must be a multiple of blockLen (8 bytes)
+*/
+int32 matrix3desDecrypt(sslCipherContext_t *ctx, unsigned char *ct,
+ unsigned char *pt, int32 len)
+{
+ int32 x, i;
+ unsigned char tmp[MAXBLOCKSIZE], tmp2[MAXBLOCKSIZE];
+
+ if (pt == NULL || ct == NULL || ctx == NULL || (len & 0x7) != 0) {
+ return -1;
+ }
+
+ /* is blocklen valid? */
+ if (ctx->des3.blocklen < 0 || ctx->des3.blocklen >
+ (int32)sizeof(ctx->des3.IV)) {
+ return -1;
+ }
+ for (i = 0; i < len; i += ctx->des3.blocklen) {
+ /* decrypt the block from ct into tmp */
+ des3_ecb_decrypt(ct, tmp, &ctx->des3);
+ /* xor IV against the plaintext of the previous step */
+ for (x = 0; x < ctx->des3.blocklen; x++) {
+ /* copy CT in case ct == pt */
+ tmp2[x] = ct[x];
+ /* actually decrypt the byte */
+ pt[x] = tmp[x] ^ ctx->des3.IV[x];
+ }
+ /* replace IV with this current ciphertext */
+ for (x = 0; x < ctx->des3.blocklen; x++) {
+ ctx->des3.IV[x] = tmp2[x];
+ }
+ ct += ctx->des3.blocklen;
+ if (ctx->des3.explicitIV) {
+/*
+ An explict IV mode has an additional block of random data that
+ we dismiss here. It is not part of the MAC. The TLS 1.1 spec
+ isn't explicit about this, but it only makes sense since the
+ extra block is used to derive the IV for the remainder of the
+ message. In theory (DTLS for example) the actual decrypted block
+ could have been received out of order and the first block would
+ not decrypt to the plaintext it originally was anyway.
+
+ It is easiest to simply remove the first block in this cipher
+ code here. If we wait until we get back into matrixSslDecode
+ we have to deal with a bunch of sslBuf_t manipulations which is
+ ugly.
+*/
+ if (i != 0) {
+ pt += ctx->des3.blocklen;
+ }
+ } else {
+ pt += ctx->des3.blocklen;
+ }
+ }
+#ifdef CLEAN_STACK
+ psZeromem(tmp, sizeof(tmp));
+ psZeromem(tmp2, sizeof(tmp2));
+#endif /* CLEAN_STACK */
+ return len;
+}
+
+/******************************************************************************/
+/*
+ 3DES implementation below
+*/
+static void cookey(const ulong32 *raw1, ulong32 *keyout)
+{
+ ulong32 *cook;
+ const ulong32 *raw0;
+ ulong32 dough[32];
+ int32 i;
+
+ cook = dough;
+ for(i=0; i < 16; i++, raw1++) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ *cook |= (*raw1 & 0x00fc0000L) >> 10;
+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+ *cook = (*raw0 & 0x0003f000L) << 12;
+ *cook |= (*raw0 & 0x0000003fL) << 16;
+ *cook |= (*raw1 & 0x0003f000L) >> 4;
+ *cook++ |= (*raw1 & 0x0000003fL);
+ }
+
+ psMemcpy(keyout, dough, sizeof dough);
+ psBurnStack(sizeof(ulong32 *) * 2 + sizeof(ulong32)*32 + sizeof(int32));
+}
+
+
+static void deskey(const unsigned char *key, short edf, ulong32 *keyout)
+{
+ ulong32 i, j, l, m, n, kn[32];
+ unsigned char pc1m[56], pcr[56];
+
+ for (j=0; j < 56; j++) {
+ l = (ulong32)pc1[j];
+ m = l & 7;
+ pc1m[j] = (unsigned char)((key[l >> 3U] & bytebit[m]) ==
+ bytebit[m] ? 1 : 0);
+ }
+
+ for (i=0; i < 16; i++) {
+ if (edf == DE1) {
+ m = (15 - i) << 1;
+ } else {
+ m = i << 1;
+ }
+ n = m + 1;
+ kn[m] = kn[n] = 0L;
+ for (j=0; j < 28; j++) {
+ l = j + (ulong32)totrot[i];
+ if (l < 28) {
+ pcr[j] = pc1m[l];
+ } else {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+ for (/*j = 28*/; j < 56; j++) {
+ l = j + (ulong32)totrot[i];
+ if (l < 56) {
+ pcr[j] = pc1m[l];
+ } else {
+ pcr[j] = pc1m[l - 28];
+ }
+ }
+ for (j=0; j < 24; j++) {
+ if ((int32)pcr[(int32)pc2[j]] != 0) {
+ kn[m] |= bigbyte[j];
+ }
+ if ((int32)pcr[(int32)pc2[j+24]] != 0) {
+ kn[n] |= bigbyte[j];
+ }
+ }
+ }
+ cookey(kn, keyout);
+ psBurnStack(sizeof(int32)*5 + sizeof(ulong32)*32 +
+ sizeof(unsigned char)*112);
+}
+
+static void desfunc(ulong32 *block, const ulong32 *keys)
+{
+ ulong32 work, right, leftt;
+ int32 cur_round;
+
+ leftt = block[0];
+ right = block[1];
+
+#ifdef SMALL_CODE
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+ right ^= work;
+ leftt ^= (work << 4);
+
+ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+ right ^= work;
+ leftt ^= (work << 16);
+
+ work = ((right >> 2) ^ leftt) & 0x33333333L;
+ leftt ^= work;
+ right ^= (work << 2);
+
+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+ leftt ^= work;
+ right ^= (work << 8);
+
+ right = ROLc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+
+ leftt ^= work;
+ right ^= work;
+ leftt = ROLc(leftt, 1);
+#else /* SMALL_CODE */
+{
+ ulong64 tmp;
+ tmp = des_ip[0][byte(leftt, 0)] ^
+ des_ip[1][byte(leftt, 1)] ^
+ des_ip[2][byte(leftt, 2)] ^
+ des_ip[3][byte(leftt, 3)] ^
+ des_ip[4][byte(right, 0)] ^
+ des_ip[5][byte(right, 1)] ^
+ des_ip[6][byte(right, 2)] ^
+ des_ip[7][byte(right, 3)];
+ leftt = (ulong32)(tmp >> 32);
+ right = (ulong32)(tmp & 0xFFFFFFFFUL);
+}
+#endif /* SMALL CODE */
+
+ for (cur_round = 0; cur_round < 8; cur_round++) {
+ work = RORc(right, 4) ^ *keys++;
+ leftt ^= SP7[work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = right ^ *keys++;
+ leftt ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+
+ work = RORc(leftt, 4) ^ *keys++;
+ right ^= SP7[ work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = leftt ^ *keys++;
+ right ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+ }
+
+#ifdef SMALL_CODE
+ right = RORc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = RORc(leftt, 1);
+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+ right ^= work;
+ leftt ^= (work << 8);
+
+ work = ((leftt >> 2) ^ right) & 0x33333333L;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+ leftt ^= work;
+ right ^= (work << 4);
+#else /* SMALL CODE */
+ {
+ ulong64 tmp;
+ tmp = des_fp[0][byte(leftt, 0)] ^
+ des_fp[1][byte(leftt, 1)] ^
+ des_fp[2][byte(leftt, 2)] ^
+ des_fp[3][byte(leftt, 3)] ^
+ des_fp[4][byte(right, 0)] ^
+ des_fp[5][byte(right, 1)] ^
+ des_fp[6][byte(right, 2)] ^
+ des_fp[7][byte(right, 3)];
+ leftt = (ulong32)(tmp >> 32);
+ right = (ulong32)(tmp & 0xFFFFFFFFUL);
+ }
+#endif /* SMALL CODE */
+
+ block[0] = right;
+ block[1] = leftt;
+ psBurnStack(sizeof(ulong32) * 4 + sizeof(int32));
+}
+
+/*
+ We don't validate DES keys against the following known weak keys.
+ Astronomically small chances of randomly getting a weak key
+ with 3DES. http://www.rsasecurity.com/rsalabs/faq/3-2-4.html
+
+ http://www.itl.nist.gov/fipspubs/fip74.htm
+ 1. E001E00lFl0lFl0l 01E001E00lFl0lFl
+ 2. FElFFElFFEOEFEOE 1FFElFFEOEFEOEFE
+ 3. E01FE01FF10EF10E 1FE01FEOOEF10EF1
+ 4. 01FE01FE01FE01FE FE01FE01FE01FE01
+ 5. 011F011F0l0E010E 1F011F0l0E0l0E01
+ 6. E0FEE0FEFlFEFlFE FEE0FEE0FEFlFEF1
+ 7. 0101010101010101
+ 8. FEFEFEFEFEFEFEFE
+ 9. E0E0E0E0FlFlFlFl
+ 10. lFlFlFlF0E0E0E0E
+*/
+int32 des3_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey)
+{
+ if (key == NULL || skey == NULL) {
+ return -1;
+ }
+
+ if( num_rounds != 0 && num_rounds != 16) {
+ return CRYPT_INVALID_ROUNDS;
+ }
+
+ if (keylen != 24) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+
+ deskey(key, EN0, skey->key.ek[0]);
+ deskey(key+8, DE1, skey->key.ek[1]);
+ deskey(key+16, EN0, skey->key.ek[2]);
+
+ deskey(key, DE1, skey->key.dk[2]);
+ deskey(key+8, EN0, skey->key.dk[1]);
+ deskey(key+16, DE1, skey->key.dk[0]);
+
+ return CRYPT_OK;
+}
+
+int32 des_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey)
+{
+
+ if (num_rounds != 0 && num_rounds != 16) {
+ return CRYPT_INVALID_ROUNDS;
+ }
+
+ if (keylen != 8) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+
+ deskey(key, EN0, skey->key.ek[0]);
+ deskey(key, DE1, skey->key.dk[0]);
+
+ return CRYPT_OK;
+}
+
+void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key)
+{
+ ulong32 work[2];
+
+ LOAD32H(work[0], pt+0);
+ LOAD32H(work[1], pt+4);
+ desfunc(work, key->key.ek[0]);
+ desfunc(work, key->key.ek[1]);
+ desfunc(work, key->key.ek[2]);
+ STORE32H(work[0],ct+0);
+ STORE32H(work[1],ct+4);
+}
+
+void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key)
+{
+ ulong32 work[2];
+
+ LOAD32H(work[0], pt+0);
+ LOAD32H(work[1], pt+4);
+ desfunc(work, key->key.ek[0]);
+ STORE32H(work[0],ct+0);
+ STORE32H(work[1],ct+4);
+}
+
+void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key)
+{
+ ulong32 work[2];
+
+ LOAD32H(work[0], ct+0);
+ LOAD32H(work[1], ct+4);
+ desfunc(work, key->key.dk[0]);
+ desfunc(work, key->key.dk[1]);
+ desfunc(work, key->key.dk[2]);
+ STORE32H(work[0],pt+0);
+ STORE32H(work[1],pt+4);
+}
+
+void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key)
+{
+ ulong32 work[2];
+ LOAD32H(work[0], ct+0);
+ LOAD32H(work[1], ct+4);
+ desfunc(work, key->key.dk[0]);
+ STORE32H(work[0],pt+0);
+ STORE32H(work[1],pt+4);
+}
+
+int32 des3_keysize(int32 *desired_keysize)
+{
+ if(*desired_keysize < 24) {
+ return CRYPT_INVALID_KEYSIZE;
+ }
+ *desired_keysize = 24;
+ return CRYPT_OK;
+}
+
+/******************************************************************************/
+/*
+ Generate a 3DES key given a password and salt value.
+ We use PKCS#5 2.0 PBKDF1 key derivation format with MD5 and count == 1 per:
+ http://www.rsasecurity.com/rsalabs/pkcs/pkcs-5/index.html
+
+ This key is compatible with the algorithm used by OpenSSL to encrypt keys
+ generated with 'openssl genrsa'. If other encryption formats are used
+ (for example PBKDF2), or an iteration count > 0 is used, they are not
+ compatible with this simple implementation. OpenSSL provides many options
+ for converting key formats to the one used here.
+
+ A 3DES key is 24 bytes long, to generate it with this algorithm,
+ we md5 hash the password and salt for the first 16 bytes. We then
+ hash these first 16 bytes with the password and salt again, generating
+ another 16 bytes. We take the first 16 bytes and 8 of the second 16 to
+ form the 24 byte key.
+
+ salt is assumed to point to 8 bytes of data
+ key is assumed to point to 24 bytes of data
+*/
+void generate3DESKey(unsigned char *pass, int32 passlen, unsigned char *salt,
+ unsigned char *key)
+{
+ sslMd5Context_t state;
+ unsigned char md5[SSL_MD5_HASH_SIZE];
+
+ matrixMd5Init(&state);
+ matrixMd5Update(&state, pass, passlen);
+ matrixMd5Update(&state, salt, SSL_DES3_IV_LEN);
+ matrixMd5Final(&state, md5);
+ memcpy(key, md5, SSL_MD5_HASH_SIZE);
+
+ matrixMd5Init(&state);
+ matrixMd5Update(&state, md5, SSL_MD5_HASH_SIZE);
+ matrixMd5Update(&state, pass, passlen);
+ matrixMd5Update(&state, salt, SSL_DES3_IV_LEN);
+ matrixMd5Final(&state, md5);
+ memcpy(key + SSL_MD5_HASH_SIZE, md5, SSL_DES3_KEY_LEN - SSL_MD5_HASH_SIZE);
+}
+
+
+#ifdef PEERSEC_TEST
+
+int32 matrixDes3Test()
+{
+ unsigned char key[24], pt[8], ct[8], tmp[8];
+ des3_CBC skey;
+ int32 x, err;
+
+ for (x = 0; x < 8; x++) {
+ pt[x] = x;
+ }
+
+ for (x = 0; x < 24; x++) {
+ key[x] = x;
+ }
+
+ if ((err = des3_setup(key, 24, 0, &skey)) != CRYPT_OK) {
+ return err;
+ }
+
+ des3_ecb_encrypt(pt, ct, &skey);
+ des3_ecb_decrypt(ct, tmp, &skey);
+
+ if (memcmp(pt, tmp, 8) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ return CRYPT_OK;
+}
+
+int32 matrixDesTest()
+{
+ unsigned char key[8], pt[8], ct[8], tmp[8];
+ des3_CBC skey;
+ int32 x, err;
+
+ for (x = 0; x < 8; x++) {
+ pt[x] = x;
+ }
+
+ for (x = 0; x < 8; x++) {
+ key[x] = x;
+ }
+
+ if ((err = des_setup(key, 8, 0, &skey)) != CRYPT_OK) {
+ return err;
+ }
+
+ des_ecb_encrypt(pt, ct, &skey);
+ des_ecb_decrypt(ct, tmp, &skey);
+
+ if (memcmp(pt, tmp, 8) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+
+ return CRYPT_OK;
+}
+
+#endif /* PEERSEC_TEST */
+
+#endif /* USE_3DES */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/md2.c b/contrib/libs/matrixssl/src/crypto/peersec/md2.c
new file mode 100644
index 00000000000..2035328069e
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/md2.c
@@ -0,0 +1,221 @@
+/*
+ * md2.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * MD2 hash implementation
+ */
+/*
+ * 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"
+
+#ifdef USE_MD2
+
+static const unsigned char PI_SUBST[256] = {
+ 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+ 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+ 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+ 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+ 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+ 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+ 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+ 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+ 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+ 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+ 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+ 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+ 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+ 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+ 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+ 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+ 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+ 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+/* adds 16 bytes to the checksum */
+static void md2_update_chksum(hash_state *md)
+{
+ int32 j;
+ unsigned char L;
+ L = md->md2.chksum[15];
+ for (j = 0; j < 16; j++) {
+
+/* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference source code [and test vectors] say
+ otherwise.
+*/
+ L = (md->md2.chksum[j] ^= PI_SUBST[(int32)(md->md2.buf[j] ^ L)] & 255);
+ }
+}
+
+static void md2_compress(hash_state *md)
+{
+ int32 j, k;
+ unsigned char t;
+
+ /* copy block */
+ for (j = 0; j < 16; j++) {
+ md->md2.X[16+j] = md->md2.buf[j];
+ md->md2.X[32+j] = md->md2.X[j] ^ md->md2.X[16+j];
+ }
+
+ t = (unsigned char)0;
+
+ /* do 18 rounds */
+ for (j = 0; j < 18; j++) {
+ for (k = 0; k < 48; k++) {
+ t = (md->md2.X[k] ^= PI_SUBST[(int32)(t & 255)]);
+ }
+ t = (t + (unsigned char)j) & 255;
+ }
+}
+
+void matrixMd2Init(hash_state *md)
+{
+ sslAssert(md != NULL);
+
+ /* MD2 uses a zero'ed state... */
+ psZeromem(md->md2.X, sizeof(md->md2.X));
+ psZeromem(md->md2.chksum, sizeof(md->md2.chksum));
+ psZeromem(md->md2.buf, sizeof(md->md2.buf));
+ md->md2.curlen = 0;
+}
+
+int32 matrixMd2Update(hash_state *md, const unsigned char *buf, unsigned long len)
+{
+ unsigned long n;
+ sslAssert(md != NULL);
+ sslAssert(buf != NULL);
+ if (md-> md2 .curlen > sizeof(md-> md2 .buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+ while (len > 0) {
+ n = MIN(len, (16 - md->md2.curlen));
+ memcpy(md->md2.buf + md->md2.curlen, buf, (size_t)n);
+ md->md2.curlen += n;
+ buf += n;
+ len -= n;
+
+ /* is 16 bytes full? */
+ if (md->md2.curlen == 16) {
+ md2_compress(md);
+ md2_update_chksum(md);
+ md->md2.curlen = 0;
+ }
+ }
+ return CRYPT_OK;
+}
+
+int32 matrixMd2Final(hash_state * md, unsigned char *hash)
+{
+ unsigned long i, k;
+
+ sslAssert(md != NULL);
+ sslAssert(hash != NULL);
+
+ if (md->md2.curlen >= sizeof(md->md2.buf)) {
+ return CRYPT_INVALID_ARG;
+ }
+
+
+ /* pad the message */
+ k = 16 - md->md2.curlen;
+ for (i = md->md2.curlen; i < 16; i++) {
+ md->md2.buf[i] = (unsigned char)k;
+ }
+
+ /* hash and update */
+ md2_compress(md);
+ md2_update_chksum(md);
+
+ /* hash checksum */
+ memcpy(md->md2.buf, md->md2.chksum, 16);
+ md2_compress(md);
+
+ /* output is lower 16 bytes of X */
+ memcpy(hash, md->md2.X, 16);
+
+#ifdef CLEAN_STACK
+ psZeromem(md, sizeof(hash_state));
+#endif
+ return CRYPT_OK;
+}
+
+#ifdef PEERSEC_TEST
+
+int32 matrixMd2Test(void)
+{
+ static const struct {
+ char *msg;
+ unsigned char md[16];
+ } tests[] = {
+ { "",
+ {0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,
+ 0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73
+ }
+ },
+ { "a",
+ {0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,
+ 0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1
+ }
+ },
+ { "message digest",
+ {0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,
+ 0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0
+ }
+ },
+ { "abcdefghijklmnopqrstuvwxyz",
+ {0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,
+ 0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b
+ }
+ },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ {0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,
+ 0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd
+ }
+ },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ {0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,
+ 0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8
+ }
+ }
+ };
+ int32 i;
+ hash_state md;
+ unsigned char buf[16];
+
+ for (i = 0; i < (int32)(sizeof(tests) / sizeof(tests[0])); i++) {
+ matrixMd2Init(&md);
+ matrixMd2Update(&md, (unsigned char*)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ matrixMd2Final(&md, buf);
+ if (memcmp(buf, tests[i].md, 16) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+ }
+ return CRYPT_OK;
+}
+
+#endif /* PEERSEC_TEST */
+
+#endif /* USE_MD2 */
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/md5.c b/contrib/libs/matrixssl/src/crypto/peersec/md5.c
new file mode 100644
index 00000000000..171078d992a
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/md5.c
@@ -0,0 +1,401 @@
+/*
+ * md5.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * MD5 hash implementation
+ */
+/*
+ * 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"
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define G(x,y,z) (y ^ (z & (y ^ x)))
+#define H(x,y,z) (x^y^z)
+#define I(x,y,z) (y^(x|(~z)))
+
+#ifdef SMALL_CODE
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROL(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROL(a, s) + b;
+
+static const unsigned char Worder[64] = {
+ 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
+ 1,6,11,0,5,10,15,4,9,14,3,8,13,2,7,12,
+ 5,8,11,14,1,4,7,10,13,0,3,6,9,12,15,2,
+ 0,7,14,5,12,3,10,1,8,15,6,13,4,11,2,9
+};
+
+static const unsigned char Rorder[64] = {
+ 7,12,17,22,7,12,17,22,7,12,17,22,7,12,17,22,
+ 5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
+ 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,
+ 6,10,15,21,6,10,15,21,6,10,15,21,6,10,15,21
+};
+
+static const ulong32 Korder[] = {
+ 0xd76aa478UL, 0xe8c7b756UL, 0x242070dbUL, 0xc1bdceeeUL,
+ 0xf57c0fafUL, 0x4787c62aUL, 0xa8304613UL, 0xfd469501UL,
+ 0x698098d8UL, 0x8b44f7afUL, 0xffff5bb1UL, 0x895cd7beUL,
+ 0x6b901122UL, 0xfd987193UL, 0xa679438eUL, 0x49b40821UL,
+ 0xf61e2562UL, 0xc040b340UL, 0x265e5a51UL, 0xe9b6c7aaUL,
+ 0xd62f105dUL, 0x02441453UL, 0xd8a1e681UL, 0xe7d3fbc8UL,
+ 0x21e1cde6UL, 0xc33707d6UL, 0xf4d50d87UL, 0x455a14edUL,
+ 0xa9e3e905UL, 0xfcefa3f8UL, 0x676f02d9UL, 0x8d2a4c8aUL,
+ 0xfffa3942UL, 0x8771f681UL, 0x6d9d6122UL, 0xfde5380cUL,
+ 0xa4beea44UL, 0x4bdecfa9UL, 0xf6bb4b60UL, 0xbebfbc70UL,
+ 0x289b7ec6UL, 0xeaa127faUL, 0xd4ef3085UL, 0x04881d05UL,
+ 0xd9d4d039UL, 0xe6db99e5UL, 0x1fa27cf8UL, 0xc4ac5665UL,
+ 0xf4292244UL, 0x432aff97UL, 0xab9423a7UL, 0xfc93a039UL,
+ 0x655b59c3UL, 0x8f0ccc92UL, 0xffeff47dUL, 0x85845dd1UL,
+ 0x6fa87e4fUL, 0xfe2ce6e0UL, 0xa3014314UL, 0x4e0811a1UL,
+ 0xf7537e82UL, 0xbd3af235UL, 0x2ad7d2bbUL, 0xeb86d391UL,
+ 0xe1f27f3aUL, 0xf5710fb0UL, 0xada0e5c4UL, 0x98e4c919UL
+ };
+#else /* SMALL_CODE */
+
+#define FF(a,b,c,d,M,s,t) \
+ a = (a + F(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define GG(a,b,c,d,M,s,t) \
+ a = (a + G(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define HH(a,b,c,d,M,s,t) \
+ a = (a + H(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#define II(a,b,c,d,M,s,t) \
+ a = (a + I(b,c,d) + M + t); a = ROLc(a, s) + b;
+
+#endif /* SMALL_CODE */
+
+#ifdef CLEAN_STACK
+static void _md5_compress(hash_state *md)
+#else
+static void md5_compress(hash_state *md)
+#endif /* CLEAN_STACK */
+{
+ unsigned long i, W[16], a, b, c, d;
+#ifdef SMALL_CODE
+ ulong32 t;
+#endif
+
+ sslAssert(md != NULL);
+
+/*
+ copy the state into 512-bits into W[0..15]
+ */
+ for (i = 0; i < 16; i++) {
+ LOAD32L(W[i], md->md5.buf + (4*i));
+ }
+
+/*
+ copy state
+ */
+ a = md->md5.state[0];
+ b = md->md5.state[1];
+ c = md->md5.state[2];
+ d = md->md5.state[3];
+
+#ifdef SMALL_CODE
+ for (i = 0; i < 16; ++i) {
+ FF(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 32; ++i) {
+ GG(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 48; ++i) {
+ HH(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 64; ++i) {
+ II(a,b,c,d,W[Worder[i]],Rorder[i],Korder[i]);
+ t = d; d = c; c = b; b = a; a = t;
+ }
+
+#else /* SMALL_CODE */
+
+ FF(a,b,c,d,W[0],7,0xd76aa478UL)
+ FF(d,a,b,c,W[1],12,0xe8c7b756UL)
+ FF(c,d,a,b,W[2],17,0x242070dbUL)
+ FF(b,c,d,a,W[3],22,0xc1bdceeeUL)
+ FF(a,b,c,d,W[4],7,0xf57c0fafUL)
+ FF(d,a,b,c,W[5],12,0x4787c62aUL)
+ FF(c,d,a,b,W[6],17,0xa8304613UL)
+ FF(b,c,d,a,W[7],22,0xfd469501UL)
+ FF(a,b,c,d,W[8],7,0x698098d8UL)
+ FF(d,a,b,c,W[9],12,0x8b44f7afUL)
+ FF(c,d,a,b,W[10],17,0xffff5bb1UL)
+ FF(b,c,d,a,W[11],22,0x895cd7beUL)
+ FF(a,b,c,d,W[12],7,0x6b901122UL)
+ FF(d,a,b,c,W[13],12,0xfd987193UL)
+ FF(c,d,a,b,W[14],17,0xa679438eUL)
+ FF(b,c,d,a,W[15],22,0x49b40821UL)
+ GG(a,b,c,d,W[1],5,0xf61e2562UL)
+ GG(d,a,b,c,W[6],9,0xc040b340UL)
+ GG(c,d,a,b,W[11],14,0x265e5a51UL)
+ GG(b,c,d,a,W[0],20,0xe9b6c7aaUL)
+ GG(a,b,c,d,W[5],5,0xd62f105dUL)
+ GG(d,a,b,c,W[10],9,0x02441453UL)
+ GG(c,d,a,b,W[15],14,0xd8a1e681UL)
+ GG(b,c,d,a,W[4],20,0xe7d3fbc8UL)
+ GG(a,b,c,d,W[9],5,0x21e1cde6UL)
+ GG(d,a,b,c,W[14],9,0xc33707d6UL)
+ GG(c,d,a,b,W[3],14,0xf4d50d87UL)
+ GG(b,c,d,a,W[8],20,0x455a14edUL)
+ GG(a,b,c,d,W[13],5,0xa9e3e905UL)
+ GG(d,a,b,c,W[2],9,0xfcefa3f8UL)
+ GG(c,d,a,b,W[7],14,0x676f02d9UL)
+ GG(b,c,d,a,W[12],20,0x8d2a4c8aUL)
+ HH(a,b,c,d,W[5],4,0xfffa3942UL)
+ HH(d,a,b,c,W[8],11,0x8771f681UL)
+ HH(c,d,a,b,W[11],16,0x6d9d6122UL)
+ HH(b,c,d,a,W[14],23,0xfde5380cUL)
+ HH(a,b,c,d,W[1],4,0xa4beea44UL)
+ HH(d,a,b,c,W[4],11,0x4bdecfa9UL)
+ HH(c,d,a,b,W[7],16,0xf6bb4b60UL)
+ HH(b,c,d,a,W[10],23,0xbebfbc70UL)
+ HH(a,b,c,d,W[13],4,0x289b7ec6UL)
+ HH(d,a,b,c,W[0],11,0xeaa127faUL)
+ HH(c,d,a,b,W[3],16,0xd4ef3085UL)
+ HH(b,c,d,a,W[6],23,0x04881d05UL)
+ HH(a,b,c,d,W[9],4,0xd9d4d039UL)
+ HH(d,a,b,c,W[12],11,0xe6db99e5UL)
+ HH(c,d,a,b,W[15],16,0x1fa27cf8UL)
+ HH(b,c,d,a,W[2],23,0xc4ac5665UL)
+ II(a,b,c,d,W[0],6,0xf4292244UL)
+ II(d,a,b,c,W[7],10,0x432aff97UL)
+ II(c,d,a,b,W[14],15,0xab9423a7UL)
+ II(b,c,d,a,W[5],21,0xfc93a039UL)
+ II(a,b,c,d,W[12],6,0x655b59c3UL)
+ II(d,a,b,c,W[3],10,0x8f0ccc92UL)
+ II(c,d,a,b,W[10],15,0xffeff47dUL)
+ II(b,c,d,a,W[1],21,0x85845dd1UL)
+ II(a,b,c,d,W[8],6,0x6fa87e4fUL)
+ II(d,a,b,c,W[15],10,0xfe2ce6e0UL)
+ II(c,d,a,b,W[6],15,0xa3014314UL)
+ II(b,c,d,a,W[13],21,0x4e0811a1UL)
+ II(a,b,c,d,W[4],6,0xf7537e82UL)
+ II(d,a,b,c,W[11],10,0xbd3af235UL)
+ II(c,d,a,b,W[2],15,0x2ad7d2bbUL)
+ II(b,c,d,a,W[9],21,0xeb86d391UL)
+#endif /* SMALL_CODE */
+
+ md->md5.state[0] = md->md5.state[0] + a;
+ md->md5.state[1] = md->md5.state[1] + b;
+ md->md5.state[2] = md->md5.state[2] + c;
+ md->md5.state[3] = md->md5.state[3] + d;
+}
+
+#ifdef CLEAN_STACK
+static void md5_compress(hash_state *md)
+{
+ _md5_compress(md);
+ psBurnStack(sizeof(unsigned long) * 21);
+}
+#endif /* CLEAN_STACK */
+
+void matrixMd5Init(hash_state * md)
+{
+ sslAssert(md != NULL);
+ md->md5.state[0] = 0x67452301UL;
+ md->md5.state[1] = 0xefcdab89UL;
+ md->md5.state[2] = 0x98badcfeUL;
+ md->md5.state[3] = 0x10325476UL;
+ md->md5.curlen = 0;
+#ifdef USE_INT64
+ md->md5.length = 0;
+#else
+ md->md5.lengthHi = 0;
+ md->md5.lengthLo = 0;
+#endif /* USE_INT64 */
+}
+
+void matrixMd5Update(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+ unsigned long n;
+
+ sslAssert(md != NULL);
+ sslAssert(buf != NULL);
+ while (len > 0) {
+ n = MIN(len, (64 - md->md5.curlen));
+ memcpy(md->md5.buf + md->md5.curlen, buf, (size_t)n);
+ md->md5.curlen += n;
+ buf += n;
+ len -= n;
+
+/*
+ is 64 bytes full?
+ */
+ if (md->md5.curlen == 64) {
+ md5_compress(md);
+#ifdef USE_INT64
+ md->md5.length += 512;
+#else
+ n = (md->md5.lengthLo + 512) & 0xFFFFFFFFL;
+ if (n < md->md5.lengthLo) {
+ md->md5.lengthHi++;
+ }
+ md->md5.lengthLo = n;
+#endif /* USE_INT64 */
+ md->md5.curlen = 0;
+ }
+ }
+}
+
+int32 matrixMd5Final(hash_state * md, unsigned char *hash)
+{
+ int32 i;
+#ifndef USE_INT64
+ unsigned long n;
+#endif
+
+ sslAssert(md != NULL);
+ if (hash == NULL) {
+ return -1;
+ }
+
+/*
+ increase the length of the message
+ */
+#ifdef USE_INT64
+ md->md5.length += md->md5.curlen << 3;
+#else
+ n = (md->md5.lengthLo + (md->md5.curlen << 3)) & 0xFFFFFFFFL;
+ if (n < md->md5.lengthLo) {
+ md->md5.lengthHi++;
+ }
+ md->md5.lengthHi += (md->md5.curlen >> 29);
+ md->md5.lengthLo = n;
+#endif /* USE_INT64 */
+
+/*
+ append the '1' bit
+ */
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0x80;
+
+/*
+ if the length is currently above 56 bytes we append zeros then compress.
+ Then we can fall back to padding zeros and length encoding like normal.
+ */
+ if (md->md5.curlen > 56) {
+ while (md->md5.curlen < 64) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+ md5_compress(md);
+ md->md5.curlen = 0;
+ }
+
+/*
+ pad upto 56 bytes of zeroes
+ */
+ while (md->md5.curlen < 56) {
+ md->md5.buf[md->md5.curlen++] = (unsigned char)0;
+ }
+/*
+ store length
+ */
+#ifdef USE_INT64
+ STORE64L(md->md5.length, md->md5.buf+56);
+#else
+ STORE32L(md->md5.lengthLo, md->md5.buf+56);
+ STORE32L(md->md5.lengthHi, md->md5.buf+60);
+#endif /* USE_INT64 */
+ md5_compress(md);
+
+/*
+ copy output
+ */
+ for (i = 0; i < 4; i++) {
+ STORE32L(md->md5.state[i], hash+(4*i));
+ }
+#ifdef CLEAN_STACK
+ psZeromem(md, sizeof(hash_state));
+#endif /* CLEAN_STACK */
+ return 16;
+}
+
+#ifdef PEERSEC_TEST
+
+int32 matrixMd5Test()
+{
+ static const struct {
+ char *msg;
+ unsigned char hash[16];
+ } tests[] = {
+ { "",
+ { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04,
+ 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } },
+ { "a",
+ {0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8,
+ 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } },
+ { "abc",
+ { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0,
+ 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } },
+ { "message digest",
+ { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d,
+ 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } },
+ { "abcdefghijklmnopqrstuvwxyz",
+ { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00,
+ 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } },
+ { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5,
+ 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } },
+ { "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55,
+ 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } },
+ { NULL, { 0 } }
+ };
+
+ int32 i;
+ unsigned char tmp[16];
+ hash_state md;
+
+ for (i = 0; tests[i].msg != NULL; i++) {
+ matrixMd5Init(&md);
+ matrixMd5Update(&md, (unsigned char *)tests[i].msg, (unsigned long)strlen(tests[i].msg));
+ matrixMd5Final(&md, tmp);
+ if (memcmp(tmp, tests[i].hash, 16) != 0) {
+ return CRYPT_FAIL_TESTVECTOR;
+ }
+ }
+ return CRYPT_OK;
+}
+#endif /* PEERSEC_TEST */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/mpi.c b/contrib/libs/matrixssl/src/crypto/peersec/mpi.c
new file mode 100644
index 00000000000..8b2a2736ebc
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/mpi.c
@@ -0,0 +1,3667 @@
+/*
+ * mpi.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * multiple-precision integer library
+ */
+/*
+ * 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"
+#include <stdarg.h>
+
+#ifndef USE_MPI2
+
+static int32 mp_exptmod_fast (psPool_t *pool, mp_int * G, mp_int * X,
+ mp_int * P, mp_int * Y, int32 redmode);
+
+/******************************************************************************/
+/*
+ FUTURE
+ 1. Convert the mp_init and mp_clear functions to not use malloc + free,
+ but to use static storage within the bignum variable instead - but
+ how to handle grow()? Maybe use a simple memory allocator
+ 2. verify stack usage of all functions and use of MP_LOW_MEM:
+ fast_mp_montgomery_reduce
+ fast_s_mp_mul_digs
+ fast_s_mp_sqr
+ fast_s_mp_mul_high_digs
+ 3. HAC stands for Handbook of Applied Cryptography
+ http://www.cacr.math.uwaterloo.ca/hac/
+*/
+/******************************************************************************/
+/*
+ Utility functions
+*/
+void psZeromem(void *dst, size_t len)
+{
+ unsigned char *mem = (unsigned char *)dst;
+
+ if (dst == NULL) {
+ return;
+ }
+ while (len-- > 0) {
+ *mem++ = 0;
+ }
+}
+
+void psBurnStack(unsigned long len)
+{
+ unsigned char buf[32];
+
+ psZeromem(buf, sizeof(buf));
+ if (len > (unsigned long)sizeof(buf)) {
+ psBurnStack(len - sizeof(buf));
+ }
+}
+
+/******************************************************************************/
+/*
+ Multiple precision integer functions
+ Note: we don't use va_args here to prevent portability issues.
+*/
+int32 _mp_init_multi(psPool_t *pool, mp_int *mp0, mp_int *mp1, mp_int *mp2,
+ mp_int *mp3, mp_int *mp4, mp_int *mp5,
+ mp_int *mp6, mp_int *mp7)
+{
+ mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
+ int32 n = 0; /* Number of ok inits */
+ mp_int *tempArray[9];
+
+ tempArray[0] = mp0;
+ tempArray[1] = mp1;
+ tempArray[2] = mp2;
+ tempArray[3] = mp3;
+ tempArray[4] = mp4;
+ tempArray[5] = mp5;
+ tempArray[6] = mp6;
+ tempArray[7] = mp7;
+ tempArray[8] = NULL;
+
+ while (tempArray[n] != NULL) {
+ if (mp_init(pool, tempArray[n]) != MP_OKAY) {
+ res = MP_MEM;
+ break;
+ }
+ n++;
+ }
+
+ if (res == MP_MEM) {
+ n = 0;
+ while (tempArray[n] != NULL) {
+ mp_clear(tempArray[n]);
+ n++;
+ }
+ }
+ return res; /* Assumed ok, if error flagged above. */
+}
+/******************************************************************************/
+/*
+ Reads a unsigned char array, assumes the msb is stored first [big endian]
+ */
+int32 mp_read_unsigned_bin (mp_int * a, unsigned char *b, int32 c)
+{
+ int32 res;
+
+/*
+ Make sure there are at least two digits.
+ */
+ if (a->alloc < 2) {
+ if ((res = mp_grow(a, 2)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ Zero the int32.
+ */
+ mp_zero (a);
+
+/*
+ read the bytes in
+ */
+ while (c-- > 0) {
+ if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+ return res;
+ }
+
+#ifndef MP_8BIT
+ a->dp[0] |= *b++;
+ a->used += 1;
+#else
+ a->dp[0] = (*b & MP_MASK);
+ a->dp[1] |= ((*b++ >> 7U) & 1);
+ a->used += 2;
+#endif /* MP_8BIT */
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Compare two ints (signed)
+ */
+int32 mp_cmp (mp_int * a, mp_int * b)
+{
+/*
+ compare based on sign
+ */
+ if (a->sign != b->sign) {
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ } else {
+ return MP_GT;
+ }
+ }
+
+/*
+ compare digits
+ */
+ if (a->sign == MP_NEG) {
+ /* if negative compare opposite direction */
+ return mp_cmp_mag(b, a);
+ } else {
+ return mp_cmp_mag(a, b);
+ }
+}
+
+/******************************************************************************/
+/*
+ Store in unsigned [big endian] format.
+*/
+int32 mp_to_unsigned_bin(psPool_t *pool, mp_int * a, unsigned char *b)
+{
+ int32 x, res;
+ mp_int t;
+
+ if ((res = mp_init_copy(pool, &t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ x = 0;
+ while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+ b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+ b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif /* MP_8BIT */
+ if ((res = mp_div_2d (pool, &t, 8, &t, NULL)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+ bn_reverse (b, x);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+void _mp_clear_multi(mp_int *mp0, mp_int *mp1, mp_int *mp2, mp_int *mp3,
+ mp_int *mp4, mp_int *mp5, mp_int *mp6, mp_int *mp7)
+{
+ int32 n = 0; /* Number of ok inits */
+
+ mp_int *tempArray[9];
+
+ tempArray[0] = mp0;
+ tempArray[1] = mp1;
+ tempArray[2] = mp2;
+ tempArray[3] = mp3;
+ tempArray[4] = mp4;
+ tempArray[5] = mp5;
+ tempArray[6] = mp6;
+ tempArray[7] = mp7;
+ tempArray[8] = NULL;
+
+ for (n = 0; tempArray[n] != NULL; n++) {
+ mp_clear(tempArray[n]);
+ }
+}
+
+/******************************************************************************/
+/*
+ Init a new mp_int.
+*/
+int32 mp_init (psPool_t *pool, mp_int * a)
+{
+ int32 i;
+/*
+ allocate memory required and clear it
+ */
+ a->dp = OPT_CAST(mp_digit) psMalloc(pool, sizeof (mp_digit) * MP_PREC);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+/*
+ set the digits to zero
+ */
+ for (i = 0; i < MP_PREC; i++) {
+ a->dp[i] = 0;
+ }
+/*
+ set the used to zero, allocated digits to the default precision and sign
+ to positive
+ */
+ a->used = 0;
+ a->alloc = MP_PREC;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ clear one (frees).
+ */
+void mp_clear (mp_int * a)
+{
+ int32 i;
+/*
+ only do anything if a hasn't been freed previously
+ */
+ if (a->dp != NULL) {
+/*
+ first zero the digits
+ */
+ for (i = 0; i < a->used; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* free ram */
+ psFree (a->dp);
+
+/*
+ reset members to make debugging easier
+ */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+
+/******************************************************************************/
+/*
+ Get the size for an unsigned equivalent.
+ */
+int32 mp_unsigned_bin_size (mp_int * a)
+{
+ int32 size = mp_count_bits (a);
+
+ return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+/******************************************************************************/
+/*
+ Trim unused digits
+
+ This is used to ensure that leading zero digits are trimed and the
+ leading "used" digit will be non-zero. Typically very fast. Also fixes
+ the sign if there are no more leading digits
+*/
+void mp_clamp (mp_int * a)
+{
+/*
+ decrease used while the most significant digit is zero.
+ */
+ while (a->used > 0 && a->dp[a->used - 1] == 0) {
+ --(a->used);
+ }
+
+/*
+ reset the sign flag if used == 0
+ */
+ if (a->used == 0) {
+ a->sign = MP_ZPOS;
+ }
+}
+
+/******************************************************************************/
+/*
+ Shift left by a certain bit count.
+ */
+int32 mp_mul_2d (mp_int * a, int32 b, mp_int * c)
+{
+ mp_digit d;
+ int32 res;
+
+/*
+ Copy
+ */
+ if (a != c) {
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (c->alloc < (int32)(c->used + b/DIGIT_BIT + 1)) {
+ if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ Shift by as many digits in the bit count
+ */
+ if (b >= (int32)DIGIT_BIT) {
+ if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ shift any bit count < DIGIT_BIT
+ */
+ d = (mp_digit) (b % DIGIT_BIT);
+ if (d != 0) {
+ mp_digit *tmpc, shift, mask, r, rr;
+ int32 x;
+
+/*
+ bitmask for carries
+ */
+ mask = (((mp_digit)1) << d) - 1;
+
+/*
+ shift for msbs
+ */
+ shift = DIGIT_BIT - d;
+
+ /* alias */
+ tmpc = c->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+/*
+ get the higher bits of the current word
+ */
+ rr = (*tmpc >> shift) & mask;
+
+/*
+ shift the current word and OR in the carry
+ */
+ *tmpc = ((*tmpc << d) | r) & MP_MASK;
+ ++tmpc;
+
+/*
+ set the carry to the carry bits of the current word
+ */
+ r = rr;
+ }
+
+/*
+ set final carry
+ */
+ if (r != 0) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Set to zero.
+ */
+void mp_zero (mp_int * a)
+{
+ int n;
+ mp_digit *tmp;
+
+ a->sign = MP_ZPOS;
+ a->used = 0;
+
+ tmp = a->dp;
+ for (n = 0; n < a->alloc; n++) {
+ *tmp++ = 0;
+ }
+}
+
+#ifdef MP_LOW_MEM
+#define TAB_SIZE 32
+#else
+#define TAB_SIZE 256
+#endif /* MP_LOW_MEM */
+
+/******************************************************************************/
+/*
+ Compare maginitude of two ints (unsigned).
+ */
+int32 mp_cmp_mag (mp_int * a, mp_int * b)
+{
+ int32 n;
+ mp_digit *tmpa, *tmpb;
+
+/*
+ compare based on # of non-zero digits
+ */
+ if (a->used > b->used) {
+ return MP_GT;
+ }
+
+ if (a->used < b->used) {
+ return MP_LT;
+ }
+
+ /* alias for a */
+ tmpa = a->dp + (a->used - 1);
+
+ /* alias for b */
+ tmpb = b->dp + (a->used - 1);
+
+/*
+ compare based on digits
+ */
+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+ if (*tmpa > *tmpb) {
+ return MP_GT;
+ }
+
+ if (*tmpa < *tmpb) {
+ return MP_LT;
+ }
+ }
+ return MP_EQ;
+}
+
+/******************************************************************************/
+/*
+ computes Y == G**X mod P, HAC pp.616, Algorithm 14.85
+
+ Uses a left-to-right k-ary sliding window to compute the modular
+ exponentiation. The value of k changes based on the size of the exponent.
+
+ Uses Montgomery or Diminished Radix reduction [whichever appropriate]
+*/
+int32 mp_exptmod(psPool_t *pool, mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+
+/*
+ modulus P must be positive
+ */
+ if (P->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+/*
+ if exponent X is negative we have to recurse
+ */
+ if (X->sign == MP_NEG) {
+ mp_int tmpG, tmpX;
+ int32 err;
+
+/*
+ first compute 1/G mod P
+ */
+ if ((err = mp_init(pool, &tmpG)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_invmod(pool, G, P, &tmpG)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+
+/*
+ now get |X|
+ */
+ if ((err = mp_init(pool, &tmpX)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ mp_clear(&tmpX);
+ return err;
+ }
+
+/*
+ and now compute (1/G)**|X| instead of G**X [X < 0]
+ */
+ err = mp_exptmod(pool, &tmpG, &tmpX, P, Y);
+ mp_clear(&tmpG);
+ mp_clear(&tmpX);
+ return err;
+ }
+
+/*
+ if the modulus is odd or dr != 0 use the fast method
+ */
+ if (mp_isodd (P) == 1) {
+ return mp_exptmod_fast (pool, G, X, P, Y, 0);
+ } else {
+/*
+ no exptmod for evens
+ */
+ return MP_VAL;
+ }
+}
+
+/******************************************************************************/
+/*
+ Call only from mp_exptmod to make sure this fast version qualifies
+*/
+static int32 mp_exptmod_fast(psPool_t *pool, mp_int * G, mp_int * X,
+ mp_int * P, mp_int * Y, int32 redmode)
+{
+ mp_int M[TAB_SIZE], res;
+ mp_digit buf, mp;
+ int32 err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+
+
+/*
+ use a pointer to the reduction algorithm. This allows us to use
+ one of many reduction algorithms without modding the guts of
+ the code with if statements everywhere.
+ */
+ int32 (*redux)(mp_int*,mp_int*,mp_digit);
+
+/*
+ find window size
+ */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+/*
+ init M array
+ init first cell
+ */
+ if ((err = mp_init(pool, &M[1])) != MP_OKAY) {
+ return err;
+ }
+
+/*
+ now init the second half of the array
+ */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(pool, &M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear(&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+
+/*
+ now setup montgomery
+ */
+ if ((err = mp_montgomery_setup(P, &mp)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+/*
+ automatically pick the comba one if available
+ */
+ if (((P->used * 2 + 1) < MP_WARRAY) &&
+ P->used < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ redux = fast_mp_montgomery_reduce;
+ } else {
+/*
+ use slower baseline Montgomery method
+ */
+ redux = mp_montgomery_reduce;
+ }
+
+/*
+ setup result
+ */
+ if ((err = mp_init(pool, &res)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+/*
+ create M table. The first half of the table is not computed
+ though accept for M[0] and M[1]
+*/
+
+/*
+ now we need R mod m
+ */
+ if ((err = mp_montgomery_calc_normalization(&res, P)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+/*
+ now set M[1] to G * R mod m
+ */
+ if ((err = mp_mulmod(pool, G, &res, P, &M[1])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+/*
+ compute the value at M[1<<(winsize-1)] by squaring
+ M[1] (winsize-1) times
+*/
+ if ((err = mp_copy(&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ if ((err = mp_sqr(pool, &M[1 << (winsize - 1)],
+ &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&M[1 << (winsize - 1)], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+/*
+ create upper table
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul(pool, &M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&M[x], P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+/*
+ set initial mode and bit cnt
+ */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+/*
+ grab next digit as required
+ */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits so break */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int)DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (mp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+/*
+ if the bit is zero and mode == 0 then we ignore it
+ These represent the leading zero bits before the first 1 bit
+ in the exponent. Technically this opt is not required but it
+ does lower the # of trivial squaring/reductions used
+*/
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+/*
+ if the bit is zero and mode == 1 then we square
+ */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (pool, &res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+/*
+ else we add it to the window
+ */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+/*
+ ok window is filled so square as required and multiply
+ square first
+ */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr(pool, &res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul(pool, &res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+/*
+ empty window and reset
+ */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+/*
+ if bits remain then square/multiply
+ */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr(pool, &res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+/*
+ get next bit of the window
+ */
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+/*
+ then multiply
+ */
+ if ((err = mp_mul(pool, &res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+/*
+ fixup result if Montgomery reduction is used
+ recall that any value in a Montgomery system is
+ actually multiplied by R mod n. So we have
+ to reduce one more time to cancel out the factor of R.
+*/
+ if ((err = redux(&res, P, mp)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+/*
+ swap res with Y
+ */
+ mp_exch(&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear(&res);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear(&M[x]);
+ }
+ return err;
+}
+
+/******************************************************************************/
+/*
+ Grow as required
+ */
+int32 mp_grow (mp_int * a, int32 size)
+{
+ int32 i;
+ mp_digit *tmp;
+
+/*
+ If the alloc size is smaller alloc more ram.
+ */
+ if (a->alloc < size) {
+/*
+ ensure there are always at least MP_PREC digits extra on top
+ */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+/*
+ Reallocate the array a->dp
+
+ We store the return in a temporary variable in case the operation
+ failed we don't want to overwrite the dp member of a.
+*/
+ tmp = OPT_CAST(mp_digit) psRealloc(a->dp, sizeof (mp_digit) * size);
+ if (tmp == NULL) {
+/*
+ reallocation failed but "a" is still valid [can be freed]
+ */
+ return MP_MEM;
+ }
+
+/*
+ reallocation succeeded so set a->dp
+ */
+ a->dp = tmp;
+
+/*
+ zero excess digits
+ */
+ i = a->alloc;
+ a->alloc = size;
+ for (; i < a->alloc; i++) {
+ a->dp[i] = 0;
+ }
+ }
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ b = |a|
+
+ Simple function copies the input and fixes the sign to positive
+*/
+int32 mp_abs (mp_int * a, mp_int * b)
+{
+ int32 res;
+
+/*
+ copy a to b
+ */
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ Force the sign of b to positive
+ */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Creates "a" then copies b into it
+ */
+int32 mp_init_copy(psPool_t *pool, mp_int * a, mp_int * b)
+{
+ int32 res;
+
+ if ((res = mp_init(pool, a)) != MP_OKAY) {
+ return res;
+ }
+ return mp_copy (b, a);
+}
+
+/******************************************************************************/
+/*
+ Reverse an array, used for radix code
+ */
+void bn_reverse (unsigned char *s, int32 len)
+{
+ int32 ix, iy;
+ unsigned char t;
+
+ ix = 0;
+ iy = len - 1;
+ while (ix < iy) {
+ t = s[ix];
+ s[ix] = s[iy];
+ s[iy] = t;
+ ++ix;
+ --iy;
+ }
+}
+
+/******************************************************************************/
+/*
+ Shift right by a certain bit count (store quotient in c, optional
+ remainder in d)
+ */
+int32 mp_div_2d(psPool_t *pool, mp_int * a, int32 b, mp_int * c, mp_int * d)
+{
+ mp_digit D, r, rr;
+ int32 x, res;
+ mp_int t;
+
+/*
+ If the shift count is <= 0 then we do no work
+ */
+ if (b <= 0) {
+ res = mp_copy (a, c);
+ if (d != NULL) {
+ mp_zero (d);
+ }
+ return res;
+ }
+
+ if ((res = mp_init(pool, &t)) != MP_OKAY) {
+ return res;
+ }
+
+/*
+ Get the remainder
+ */
+ if (d != NULL) {
+ if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+/*
+ Shift by as many digits in the bit count
+ */
+ if (b >= (int32)DIGIT_BIT) {
+ mp_rshd (c, b / DIGIT_BIT);
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ D = (mp_digit) (b % DIGIT_BIT);
+ if (D != 0) {
+ mp_digit *tmpc, mask, shift;
+
+ /* mask */
+ mask = (((mp_digit)1) << D) - 1;
+
+ /* shift for lsb */
+ shift = DIGIT_BIT - D;
+
+ /* alias */
+ tmpc = c->dp + (c->used - 1);
+
+ /* carry */
+ r = 0;
+ for (x = c->used - 1; x >= 0; x--) {
+/*
+ Get the lower bits of this word in a temp.
+ */
+ rr = *tmpc & mask;
+
+/*
+ shift the current word and mix in the carry bits from the previous word
+ */
+ *tmpc = (*tmpc >> D) | (r << shift);
+ --tmpc;
+
+/*
+ set the carry to the carry bits of the current word found above
+ */
+ r = rr;
+ }
+ }
+ mp_clamp (c);
+ if (d != NULL) {
+ mp_exch (&t, d);
+ }
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ copy, b = a
+ */
+int32 mp_copy (mp_int * a, mp_int * b)
+{
+ int32 res, n;
+
+/*
+ If dst == src do nothing
+ */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+/*
+ Grow dest
+ */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ Zero b and copy the parameters over
+ */
+ {
+ mp_digit *tmpa, *tmpb;
+
+ /* pointer aliases */
+ /* source */
+ tmpa = a->dp;
+
+ /* destination */
+ tmpb = b->dp;
+
+ /* copy all the digits */
+ for (n = 0; n < a->used; n++) {
+ *tmpb++ = *tmpa++;
+ }
+
+ /* clear high digits */
+ for (; n < b->used; n++) {
+ *tmpb++ = 0;
+ }
+ }
+
+/*
+ copy used count and sign
+ */
+ b->used = a->used;
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Returns the number of bits in an int32
+ */
+int32 mp_count_bits (mp_int * a)
+{
+ int32 r;
+ mp_digit q;
+
+/*
+ Shortcut
+ */
+ if (a->used == 0) {
+ return 0;
+ }
+
+/*
+ Get number of digits and add that.
+ */
+ r = (a->used - 1) * DIGIT_BIT;
+
+/*
+ Take the last digit and count the bits in it.
+ */
+ q = a->dp[a->used - 1];
+ while (q > ((mp_digit) 0)) {
+ ++r;
+ q >>= ((mp_digit) 1);
+ }
+ return r;
+}
+
+/******************************************************************************/
+/*
+ Shift left a certain amount of digits.
+ */
+int32 mp_lshd (mp_int * a, int32 b)
+{
+ int32 x, res;
+
+/*
+ If its less than zero return.
+ */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+
+/*
+ Grow to fit the new digits.
+ */
+ if (a->alloc < a->used + b) {
+ if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ {
+ mp_digit *top, *bottom;
+
+/*
+ Increment the used by the shift amount then copy upwards.
+ */
+ a->used += b;
+
+ /* top */
+ top = a->dp + a->used - 1;
+
+ /* base */
+ bottom = a->dp + a->used - 1 - b;
+
+/*
+ Much like mp_rshd this is implemented using a sliding window
+ except the window goes the otherway around. Copying from
+ the bottom to the top. see bn_mp_rshd.c for more info.
+ */
+ for (x = a->used - 1; x >= b; x--) {
+ *top-- = *bottom--;
+ }
+
+ /* zero the lower digits */
+ top = a->dp;
+ for (x = 0; x < b; x++) {
+ *top++ = 0;
+ }
+ }
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Set to a digit.
+ */
+void mp_set (mp_int * a, mp_digit b)
+{
+ mp_zero (a);
+ a->dp[0] = b & MP_MASK;
+ a->used = (a->dp[0] != 0) ? 1 : 0;
+}
+
+/******************************************************************************/
+/*
+ Swap the elements of two integers, for cases where you can't simply swap
+ the mp_int pointers around
+*/
+void mp_exch (mp_int * a, mp_int * b)
+{
+ mp_int t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+
+/******************************************************************************/
+/*
+ High level multiplication (handles sign)
+ */
+int32 mp_mul(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c)
+{
+ int32 res, neg;
+ int32 digs = a->used + b->used + 1;
+
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+/* Can we use the fast multiplier?
+
+ The fast multiplier can be used if the output will have less than
+ MP_WARRAY digits and the number of digits won't affect carry propagation
+*/
+ if ((digs < MP_WARRAY) && MIN(a->used, b->used) <=
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ res = fast_s_mp_mul_digs(pool, a, b, c, digs);
+ } else {
+ res = s_mp_mul(pool, a, b, c);
+ }
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return res;
+}
+
+/******************************************************************************/
+/*
+ c = a mod b, 0 <= c < b
+ */
+int32 mp_mod(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int t;
+ int32 res;
+
+ if ((res = mp_init(pool, &t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_div (pool, a, b, NULL, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ if (t.sign != b->sign) {
+ res = mp_add (b, &t, c);
+ } else {
+ res = MP_OKAY;
+ mp_exch (&t, c);
+ }
+
+ mp_clear (&t);
+ return res;
+}
+
+/******************************************************************************/
+/*
+ shifts with subtractions when the result is greater than b.
+
+ The method is slightly modified to shift B unconditionally upto just under
+ the leading bit of b. This saves alot of multiple precision shifting.
+*/
+int32 mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
+{
+ int32 x, bits, res;
+
+/*
+ How many bits of last digit does b use
+ */
+ bits = mp_count_bits (b) % DIGIT_BIT;
+
+ if (b->used > 1) {
+ if ((res = mp_2expt(a, (b->used - 1) * DIGIT_BIT + bits - 1)) != MP_OKAY) {
+ return res;
+ }
+ } else {
+ mp_set(a, 1);
+ bits = 1;
+ }
+
+/*
+ Now compute C = A * B mod b
+ */
+ for (x = bits - 1; x < (int32)DIGIT_BIT; x++) {
+ if ((res = mp_mul_2(a, a)) != MP_OKAY) {
+ return res;
+ }
+ if (mp_cmp_mag(a, b) != MP_LT) {
+ if ((res = s_mp_sub(a, b, a)) != MP_OKAY) {
+ return res;
+ }
+ }
+ }
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ d = a * b (mod c)
+ */
+int32 mp_mulmod(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int32 res;
+ mp_int t;
+
+ if ((res = mp_init(pool, &t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_mul (pool, a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (pool, &t, c, d);
+ mp_clear (&t);
+ return res;
+}
+
+/******************************************************************************/
+/*
+ Computes b = a*a
+ */
+#ifdef USE_SMALL_WORD
+int32 mp_sqr (psPool_t *pool, mp_int * a, mp_int * b)
+{
+ int32 res;
+
+/*
+ Can we use the fast comba multiplier?
+ */
+ if ((a->used * 2 + 1) < MP_WARRAY && a->used <
+ (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+ res = fast_s_mp_sqr (pool, a, b);
+ } else {
+ res = s_mp_sqr (pool, a, b);
+ }
+ b->sign = MP_ZPOS;
+ return res;
+}
+#endif /* USE_SMALL_WORD */
+
+/******************************************************************************/
+/*
+ Computes xR**-1 == x (mod N) via Montgomery Reduction.
+
+ This is an optimized implementation of montgomery_reduce
+ which uses the comba method to quickly calculate the columns of the
+ reduction.
+
+ Based on Algorithm 14.32 on pp.601 of HAC.
+*/
+
+int32 fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int32 ix, res, olduse;
+ mp_word W[MP_WARRAY];
+
+/*
+ Get old used count
+ */
+ olduse = x->used;
+
+/*
+ Grow a as required
+ */
+ if (x->alloc < n->used + 1) {
+ if ((res = mp_grow(x, n->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ First we have to get the digits of the input into
+ an array of double precision words W[...]
+ */
+ {
+ mp_word *_W;
+ mp_digit *tmpx;
+
+/*
+ Alias for the W[] array
+ */
+ _W = W;
+
+/*
+ Alias for the digits of x
+ */
+ tmpx = x->dp;
+
+/*
+ Copy the digits of a into W[0..a->used-1]
+ */
+ for (ix = 0; ix < x->used; ix++) {
+ *_W++ = *tmpx++;
+ }
+
+/*
+ Zero the high words of W[a->used..m->used*2]
+ */
+ for (; ix < n->used * 2 + 1; ix++) {
+ *_W++ = 0;
+ }
+ }
+
+/*
+ Now we proceed to zero successive digits from the least
+ significant upwards.
+ */
+ for (ix = 0; ix < n->used; ix++) {
+/*
+ mu = ai * m' mod b
+
+ We avoid a double precision multiplication (which isn't required) by
+ casting the value down to a mp_digit. Note this requires that
+ W[ix-1] have the carry cleared (see after the inner loop)
+ */
+ mp_digit mu;
+ mu = (mp_digit) (((W[ix] & MP_MASK) * rho) & MP_MASK);
+
+/*
+ a = a + mu * m * b**i
+
+ This is computed in place and on the fly. The multiplication by b**i
+ is handled by offseting which columns the results are added to.
+
+ Note the comba method normally doesn't handle carries in the inner loop
+ In this case we fix the carry from the previous column since the
+ Montgomery reduction requires digits of the result (so far) [see above]
+ to work. This is handled by fixing up one carry after the inner loop.
+ The carry fixups are done in order so after these loops the first
+ m->used words of W[] have the carries fixed
+ */
+ {
+ int32 iy;
+ mp_digit *tmpn;
+ mp_word *_W;
+
+/*
+ Alias for the digits of the modulus
+ */
+ tmpn = n->dp;
+
+/*
+ Alias for the columns set by an offset of ix
+ */
+ _W = W + ix;
+
+/*
+ inner loop
+ */
+ for (iy = 0; iy < n->used; iy++) {
+ *_W++ += ((mp_word)mu) * ((mp_word)*tmpn++);
+ }
+ }
+
+/*
+ Now fix carry for next digit, W[ix+1]
+ */
+ W[ix + 1] += W[ix] >> ((mp_word) DIGIT_BIT);
+ }
+
+/*
+ Now we have to propagate the carries and shift the words downward [all those
+ least significant digits we zeroed].
+ */
+ {
+ mp_digit *tmpx;
+ mp_word *_W, *_W1;
+
+/*
+ Now fix rest of carries
+ */
+
+/*
+ alias for current word
+ */
+ _W1 = W + ix;
+
+/*
+ alias for next word, where the carry goes
+ */
+ _W = W + ++ix;
+
+ for (; ix <= n->used * 2 + 1; ix++) {
+ *_W++ += *_W1++ >> ((mp_word) DIGIT_BIT);
+ }
+
+/*
+ copy out, A = A/b**n
+
+ The result is A/b**n but instead of converting from an
+ array of mp_word to mp_digit than calling mp_rshd
+ we just copy them in the right order
+ */
+
+/*
+ alias for destination word
+ */
+ tmpx = x->dp;
+
+/*
+ alias for shifted double precision result
+ */
+ _W = W + n->used;
+
+ for (ix = 0; ix < n->used + 1; ix++) {
+ *tmpx++ = (mp_digit)(*_W++ & ((mp_word) MP_MASK));
+ }
+
+/*
+ zero oldused digits, if the input a was larger than
+ m->used+1 we'll have to clear the digits
+ */
+ for (; ix < olduse; ix++) {
+ *tmpx++ = 0;
+ }
+ }
+
+/*
+ Set the max used and clamp
+ */
+ x->used = n->used + 1;
+ mp_clamp(x);
+
+/*
+ if A >= m then A = A - m
+ */
+ if (mp_cmp_mag(x, n) != MP_LT) {
+ return s_mp_sub(x, n, x);
+ }
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ High level addition (handles signs)
+ */
+int32 mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ int32 sa, sb, res;
+
+/*
+ Get sign of both inputs
+ */
+ sa = a->sign;
+ sb = b->sign;
+
+/*
+ Handle two cases, not four.
+ */
+ if (sa == sb) {
+/*
+ Both positive or both negative. Add their magnitudes, copy the sign.
+ */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+/*
+ One positive, the other negative. Subtract the one with the greater
+ magnitude from the one of the lesser magnitude. The result gets the sign of
+ the one with the greater magnitude.
+ */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ c->sign = sb;
+ res = s_mp_sub (b, a, c);
+ } else {
+ c->sign = sa;
+ res = s_mp_sub (a, b, c);
+ }
+ }
+ return res;
+}
+
+/******************************************************************************/
+/*
+ Compare a digit.
+ */
+int32 mp_cmp_d (mp_int * a, mp_digit b)
+{
+/*
+ Compare based on sign
+ */
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ }
+
+/*
+ Compare based on magnitude
+ */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+/*
+ Compare the only digit of a to b
+ */
+ if (a->dp[0] > b) {
+ return MP_GT;
+ } else if (a->dp[0] < b) {
+ return MP_LT;
+ } else {
+ return MP_EQ;
+ }
+}
+
+/******************************************************************************/
+/*
+ b = a/2
+ */
+int32 mp_div_2 (mp_int * a, mp_int * b)
+{
+ int32 x, res, oldused;
+
+/*
+ Copy
+ */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+ {
+ mp_digit r, rr, *tmpa, *tmpb;
+
+/*
+ Source alias
+ */
+ tmpa = a->dp + b->used - 1;
+
+/*
+ dest alias
+ */
+ tmpb = b->dp + b->used - 1;
+
+/*
+ carry
+ */
+ r = 0;
+ for (x = b->used - 1; x >= 0; x--) {
+/*
+ Get the carry for the next iteration
+ */
+ rr = *tmpa & 1;
+
+/*
+ Shift the current digit, add in carry and store
+ */
+ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+/*
+ Forward carry to next iteration
+ */
+ r = rr;
+ }
+
+/*
+ Zero excess digits
+ */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ mp_clamp (b);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Computes xR**-1 == x (mod N) via Montgomery Reduction
+ */
+#ifdef USE_SMALL_WORD
+int32 mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+{
+ int32 ix, res, digs;
+ mp_digit mu;
+
+/* Can the fast reduction [comba] method be used?
+
+ Note that unlike in mul you're safely allowed *less* than the available
+ columns [255 per default] since carries are fixed up in the inner loop.
+ */
+ digs = n->used * 2 + 1;
+ if ((digs < MP_WARRAY) &&
+ n->used <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_mp_montgomery_reduce (x, n, rho);
+ }
+
+/*
+ Grow the input as required.
+ */
+ if (x->alloc < digs) {
+ if ((res = mp_grow (x, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+ x->used = digs;
+
+ for (ix = 0; ix < n->used; ix++) {
+/*
+ mu = ai * rho mod b
+
+ The value of rho must be precalculated via mp_montgomery_setup()
+ such that it equals -1/n0 mod b this allows the following inner
+ loop to reduce the input one digit at a time
+ */
+ mu = (mp_digit)(((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
+
+ /* a = a + mu * m * b**i */
+ {
+ int32 iy;
+ mp_digit *tmpn, *tmpx, u;
+ mp_word r;
+
+/*
+ alias for digits of the modulus
+ */
+ tmpn = n->dp;
+
+/*
+ alias for the digits of x [the input]
+ */
+ tmpx = x->dp + ix;
+
+/*
+ set the carry to zero
+ */
+ u = 0;
+
+/*
+ Multiply and add in place
+ */
+ for (iy = 0; iy < n->used; iy++) {
+ /* compute product and sum */
+ r = ((mp_word)mu) * ((mp_word)*tmpn++) +
+ ((mp_word) u) + ((mp_word) * tmpx);
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* fix digit */
+ *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
+ }
+ /* At this point the ix'th digit of x should be zero */
+
+
+/*
+ propagate carries upwards as required
+ */
+ while (u) {
+ *tmpx += u;
+ u = *tmpx >> DIGIT_BIT;
+ *tmpx++ &= MP_MASK;
+ }
+ }
+ }
+
+/*
+ At this point the n.used'th least significant digits of x are all zero
+ which means we can shift x to the right by n.used digits and the
+ residue is unchanged.
+*/
+ /* x = x/b**n.used */
+ mp_clamp(x);
+ mp_rshd (x, n->used);
+
+ /* if x >= n then x = x - n */
+ if (mp_cmp_mag (x, n) != MP_LT) {
+ return s_mp_sub (x, n, x);
+ }
+
+ return MP_OKAY;
+}
+#endif /* USE_SMALL_WORD */
+
+/******************************************************************************/
+/*
+ Setups the montgomery reduction stuff.
+ */
+int32 mp_montgomery_setup (mp_int * n, mp_digit * rho)
+{
+ mp_digit x, b;
+
+/*
+ fast inversion mod 2**k
+
+ Based on the fact that
+
+ XA = 1 (mod 2**n) => (X(2-XA)) A = 1 (mod 2**2n)
+ => 2*X*A - X*X*A*A = 1
+ => 2*(1) - (1) = 1
+*/
+ b = n->dp[0];
+
+ if ((b & 1) == 0) {
+ return MP_VAL;
+ }
+
+ x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
+ x = (x * (2 - b * x)) & MP_MASK; /* here x*a==1 mod 2**8 */
+#if !defined(MP_8BIT)
+ x = (x * (2 - b * x)) & MP_MASK; /* here x*a==1 mod 2**8 */
+#endif /* MP_8BIT */
+#if defined(MP_64BIT) || !(defined(MP_8BIT) || defined(MP_16BIT))
+ x *= 2 - b * x; /* here x*a==1 mod 2**32 */
+#endif
+#ifdef MP_64BIT
+ x *= 2 - b * x; /* here x*a==1 mod 2**64 */
+#endif /* MP_64BIT */
+
+ /* rho = -1/m mod b */
+ *rho = (((mp_word) 1 << ((mp_word) DIGIT_BIT)) - x) & MP_MASK;
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ High level subtraction (handles signs)
+ */
+int32 mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int32 sa, sb, res;
+
+ sa = a->sign;
+ sb = b->sign;
+
+ if (sa != sb) {
+/*
+ Subtract a negative from a positive, OR subtract a positive from a
+ negative. In either case, ADD their magnitudes, and use the sign of
+ the first number.
+ */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+/*
+ Subtract a positive from a positive, OR subtract a negative
+ from a negative. First, take the difference between their
+ magnitudes, then...
+ */
+ if (mp_cmp_mag (a, b) != MP_LT) {
+/*
+ Copy the sign from the first
+ */
+ c->sign = sa;
+ /* The first has a larger or equal magnitude */
+ res = s_mp_sub (a, b, c);
+ } else {
+/*
+ The result has the *opposite* sign from the first number.
+ */
+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+/*
+ The second has a larger magnitude
+ */
+ res = s_mp_sub (b, a, c);
+ }
+ }
+ return res;
+}
+
+/******************************************************************************/
+/*
+ calc a value mod 2**b
+ */
+int32 mp_mod_2d (mp_int * a, int32 b, mp_int * c)
+{
+ int32 x, res;
+
+/*
+ if b is <= 0 then zero the int32
+ */
+ if (b <= 0) {
+ mp_zero (c);
+ return MP_OKAY;
+ }
+
+/*
+ If the modulus is larger than the value than return
+ */
+ if (b >=(int32) (a->used * DIGIT_BIT)) {
+ res = mp_copy (a, c);
+ return res;
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+
+/*
+ Zero digits above the last digit of the modulus
+ */
+ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+ c->dp[x] = 0;
+ }
+/*
+ Clear the digit that is not completely outside/inside the modulus
+ */
+ c->dp[b / DIGIT_BIT] &=
+ (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ Shift right a certain amount of digits.
+ */
+void mp_rshd (mp_int * a, int32 b)
+{
+ int32 x;
+
+/*
+ If b <= 0 then ignore it
+ */
+ if (b <= 0) {
+ return;
+ }
+
+/*
+ If b > used then simply zero it and return.
+*/
+ if (a->used <= b) {
+ mp_zero (a);
+ return;
+ }
+
+ {
+ mp_digit *bottom, *top;
+
+/*
+ Shift the digits down
+ */
+ /* bottom */
+ bottom = a->dp;
+
+ /* top [offset into digits] */
+ top = a->dp + b;
+
+/*
+ This is implemented as a sliding window where the window is b-digits long
+ and digits from the top of the window are copied to the bottom.
+
+ e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ *bottom++ = *top++;
+ }
+
+/*
+ Zero the top digits
+ */
+ for (; x < a->used; x++) {
+ *bottom++ = 0;
+ }
+ }
+
+/*
+ Remove excess digits
+ */
+ a->used -= b;
+}
+
+/******************************************************************************/
+/*
+ Low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9
+ */
+int32 s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int32 olduse, res, min, max;
+
+/*
+ Find sizes
+ */
+ min = b->used;
+ max = a->used;
+
+/*
+ init result
+ */
+ if (c->alloc < max) {
+ if ((res = mp_grow (c, max)) != MP_OKAY) {
+ return res;
+ }
+ }
+ olduse = c->used;
+ c->used = max;
+
+ {
+ mp_digit u, *tmpa, *tmpb, *tmpc;
+ int32 i;
+
+/*
+ alias for digit pointers
+ */
+ tmpa = a->dp;
+ tmpb = b->dp;
+ tmpc = c->dp;
+
+/*
+ set carry to zero
+ */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ *tmpc = *tmpa++ - *tmpb++ - u;
+
+/*
+ U = carry bit of T[i]
+ Note this saves performing an AND operation since if a carry does occur it
+ will propagate all the way to the MSB. As a result a single shift
+ is enough to get the carry
+ */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+/*
+ Now copy higher words if any, e.g. if A has more digits than B
+ */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ *tmpc = *tmpa++ - u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+/*
+ Clear digits above used (since we may not have grown result above)
+ */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+/******************************************************************************/
+/*
+ integer signed division.
+
+ c*b + d == a [e.g. a/b, c=quotient, d=remainder]
+ HAC pp.598 Algorithm 14.20
+
+ Note that the description in HAC is horribly incomplete. For example,
+ it doesn't consider the case where digits are removed from 'x' in the inner
+ loop. It also doesn't consider the case that y has fewer than three
+ digits, etc..
+
+ The overall algorithm is as described as 14.20 from HAC but fixed to
+ treat these cases.
+ */
+#ifdef MP_DIV_SMALL
+int32 mp_div(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int ta, tb, tq, q;
+ int32 res, n, n2;
+
+/*
+ is divisor zero ?
+ */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+/*
+ if a < b then q=0, r = a
+ */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+/*
+ init our temps
+ */
+ if ((res = _mp_init_multi(pool, &ta, &tb, &tq, &q, NULL, NULL, NULL, NULL) != MP_OKAY)) {
+ return res;
+ }
+
+/*
+ tq = 2^n, tb == b*2^n
+ */
+ mp_set(&tq, 1);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+ goto __ERR;
+ }
+/* old
+ if (((res = mp_copy(a, &ta)) != MP_OKAY) ||
+ ((res = mp_copy(b, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+*/
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+ ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+ if (((res = mp_div_2d(pool, &tb, 1, &tb, NULL)) != MP_OKAY) ||
+ ((res = mp_div_2d(pool, &tq, 1, &tq, NULL)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ now q == quotient and ta == remainder
+ */
+ n = a->sign;
+ n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+ }
+LBL_ERR:
+ _mp_clear_multi(&ta, &tb, &tq, &q, NULL, NULL, NULL, NULL);
+ return res;
+}
+#else /* MP_DIV_SMALL */
+
+int32 mp_div(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int q, x, y, t1, t2;
+ int32 res, n, t, i, norm, neg;
+
+/*
+ is divisor zero ?
+ */
+ if (mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+/*
+ if a < b then q=0, r = a
+ */
+ if (mp_cmp_mag(a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy(a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero(c);
+ }
+ return res;
+ }
+
+ if ((res = mp_init_size(pool, &q, a->used + 2)) != MP_OKAY) {
+ return res;
+ }
+ q.used = a->used + 2;
+
+ if ((res = mp_init(pool, &t1)) != MP_OKAY) {
+ goto LBL_Q;
+ }
+
+ if ((res = mp_init(pool, &t2)) != MP_OKAY) {
+ goto LBL_T1;
+ }
+
+ if ((res = mp_init_copy(pool, &x, a)) != MP_OKAY) {
+ goto LBL_T2;
+ }
+
+ if ((res = mp_init_copy(pool, &y, b)) != MP_OKAY) {
+ goto LBL_X;
+ }
+
+/*
+ fix the sign
+ */
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+ x.sign = y.sign = MP_ZPOS;
+
+/*
+ normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT]
+ */
+ norm = mp_count_bits(&y) % DIGIT_BIT;
+ if (norm < (int32)(DIGIT_BIT-1)) {
+ norm = (DIGIT_BIT-1) - norm;
+ if ((res = mp_mul_2d(&x, norm, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_mul_2d(&y, norm, &y)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ } else {
+ norm = 0;
+ }
+
+/*
+ note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4
+ */
+ n = x.used - 1;
+ t = y.used - 1;
+
+/*
+ while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} }
+ */
+ if ((res = mp_lshd(&y, n - t)) != MP_OKAY) { /* y = y*b**{n-t} */
+ goto LBL_Y;
+ }
+
+ while (mp_cmp(&x, &y) != MP_LT) {
+ ++(q.dp[n - t]);
+ if ((res = mp_sub(&x, &y, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ }
+
+/*
+ reset y by shifting it back down
+ */
+ mp_rshd(&y, n - t);
+
+/*
+ step 3. for i from n down to (t + 1)
+ */
+ for (i = n; i >= (t + 1); i--) {
+ if (i > x.used) {
+ continue;
+ }
+
+/*
+ step 3.1 if xi == yt then set q{i-t-1} to b-1,
+ otherwise set q{i-t-1} to (xi*b + x{i-1})/yt
+ */
+ if (x.dp[i] == y.dp[t]) {
+ q.dp[i - t - 1] = ((((mp_digit)1) << DIGIT_BIT) - 1);
+ } else {
+ mp_word tmp;
+ tmp = ((mp_word) x.dp[i]) << ((mp_word) DIGIT_BIT);
+ tmp |= ((mp_word) x.dp[i - 1]);
+ tmp /= ((mp_word) y.dp[t]);
+ if (tmp > (mp_word) MP_MASK) {
+ tmp = MP_MASK;
+ }
+ q.dp[i - t - 1] = (mp_digit) (tmp & (mp_word) (MP_MASK));
+ }
+
+/*
+ while (q{i-t-1} * (yt * b + y{t-1})) >
+ xi * b**2 + xi-1 * b + xi-2
+
+ do q{i-t-1} -= 1;
+ */
+ q.dp[i - t - 1] = (q.dp[i - t - 1] + 1) & MP_MASK;
+ do {
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1) & MP_MASK;
+
+/*
+ find left hand
+ */
+ mp_zero (&t1);
+ t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
+ t1.dp[1] = y.dp[t];
+ t1.used = 2;
+ if ((res = mp_mul_d (&t1, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+/*
+ find right hand
+ */
+ t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
+ t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
+ t2.dp[2] = x.dp[i];
+ t2.used = 3;
+ } while (mp_cmp_mag(&t1, &t2) == MP_GT);
+
+/*
+ step 3.3 x = x - q{i-t-1} * y * b**{i-t-1}
+ */
+ if ((res = mp_mul_d(&y, q.dp[i - t - 1], &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_lshd(&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ if ((res = mp_sub(&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+/*
+ if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; }
+ */
+ if (x.sign == MP_NEG) {
+ if ((res = mp_copy(&y, &t1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_lshd (&t1, i - t - 1)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+ if ((res = mp_add (&x, &t1, &x)) != MP_OKAY) {
+ goto LBL_Y;
+ }
+
+ q.dp[i - t - 1] = (q.dp[i - t - 1] - 1UL) & MP_MASK;
+ }
+ }
+
+/*
+ now q is the quotient and x is the remainder
+ [which we have to normalize]
+ */
+
+/*
+ get sign before writing to c
+ */
+ x.sign = x.used == 0 ? MP_ZPOS : a->sign;
+
+ if (c != NULL) {
+ mp_clamp(&q);
+ mp_exch(&q, c);
+ c->sign = neg;
+ }
+
+ if (d != NULL) {
+ mp_div_2d(pool, &x, norm, &x, NULL);
+ mp_exch(&x, d);
+ }
+
+ res = MP_OKAY;
+
+LBL_Y:mp_clear (&y);
+LBL_X:mp_clear (&x);
+LBL_T2:mp_clear (&t2);
+LBL_T1:mp_clear (&t1);
+LBL_Q:mp_clear (&q);
+ return res;
+}
+#endif /* MP_DIV_SMALL */
+
+/******************************************************************************/
+/*
+ multiplies |a| * |b| and only computes upto digs digits of result
+ HAC pp. 595, Algorithm 14.12 Modified so you can control how many digits
+ of output are created.
+ */
+#ifdef USE_SMALL_WORD
+int32 s_mp_mul_digs(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c, int32 digs)
+{
+ mp_int t;
+ int32 res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+/*
+ Can we use the fast multiplier?
+ */
+ if (((digs) < MP_WARRAY) &&
+ MIN (a->used, b->used) <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_digs (pool, a, b, c, digs);
+ }
+
+ if ((res = mp_init_size(pool, &t, digs)) != MP_OKAY) {
+ return res;
+ }
+ t.used = digs;
+
+/*
+ Compute the digits of the product directly
+ */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* set the carry to zero */
+ u = 0;
+
+/*
+ Limit ourselves to making digs digits of output.
+*/
+ pb = MIN (b->used, digs - ix);
+
+/*
+ Setup some aliases. Copy of the digit from a used
+ within the nested loop
+ */
+ tmpx = a->dp[ix];
+
+/*
+ An alias for the destination shifted ix places
+ */
+ tmpt = t.dp + ix;
+
+/*
+ An alias for the digits of b
+ */
+ tmpy = b->dp;
+
+/*
+ Compute the columns of the output and propagate the carry
+ */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* the new column is the lower part of the result */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry word from the result */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+/*
+ Set carry if it is placed below digs
+ */
+ if (ix + iy < digs) {
+ *tmpt = u;
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, c);
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif /* USE_SMALL_WORD */
+
+/******************************************************************************/
+/*
+ Fast (comba) multiplier
+
+ This is the fast column-array [comba] multiplier. It is designed to
+ compute the columns of the product first then handle the carries afterwards.
+ This has the effect of making the nested loops that compute the columns
+ very simple and schedulable on super-scalar processors.
+
+ This has been modified to produce a variable number of digits of output so
+ if say only a half-product is required you don't have to compute the upper
+ half (a feature required for fast Barrett reduction).
+
+ Based on Algorithm 14.12 on pp.595 of HAC.
+*/
+
+int32 fast_s_mp_mul_digs(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c,
+ int32 digs)
+{
+ int32 olduse, res, pa, ix, iz, neg;
+ mp_digit W[MP_WARRAY];
+ mp_word _W;
+
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+/*
+ grow the destination as required
+ */
+ if (c->alloc < digs) {
+ if ((res = mp_grow(c, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ number of output digits to produce
+ */
+ pa = MIN(digs, a->used + b->used);
+
+/*
+ clear the carry
+ */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int32 tx, ty;
+ int32 iy;
+ mp_digit *tmpx, *tmpy;
+
+/*
+ get offsets into the two bignums
+ */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+/*
+ setup temp aliases
+ */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+/*
+ this is the number of times the loop will iterrate, essentially its
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+/*
+ execute loop
+ */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+/*
+ store term
+ */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+/*
+ make next carry
+ */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+/*
+ store final carry
+ */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+/*
+ setup dest
+ */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ mp_digit *tmpc;
+ tmpc = c->dp;
+ for (ix = 0; ix < pa+1; ix++) {
+/*
+ now extract the previous digit [below the carry]
+ */
+ *tmpc++ = W[ix];
+ }
+
+/*
+ clear unused digits [that existed in the old copy of c]
+ */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ b = a*2
+ */
+int32 mp_mul_2 (mp_int * a, mp_int * b)
+{
+ int32 x, res, oldused;
+
+/*
+ grow to accomodate result
+ */
+ if (b->alloc < a->used + 1) {
+ if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+
+ {
+ mp_digit r, rr, *tmpa, *tmpb;
+
+ /* alias for source */
+ tmpa = a->dp;
+
+ /* alias for dest */
+ tmpb = b->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < a->used; x++) {
+
+/*
+ get what will be the *next* carry bit from the MSB of the
+ current digit
+ */
+ rr = *tmpa >> ((mp_digit)(DIGIT_BIT - 1));
+
+/*
+ now shift up this digit, add in the carry [from the previous]
+ */
+ *tmpb++ = ((*tmpa++ << ((mp_digit)1)) | r) & MP_MASK;
+
+/* copy the carry that would be from the source digit into the next
+ iteration
+ */
+ r = rr;
+ }
+
+/*
+ new leading digit?
+ */
+ if (r != 0) {
+/*
+ add a MSB which is always 1 at this point
+ */
+ *tmpb = 1;
+ ++(b->used);
+ }
+
+/*
+ now zero any excess digits on the destination that we didn't write to
+ */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ multiply by a digit
+ */
+int32 mp_mul_d(mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit u, *tmpa, *tmpc;
+ mp_word r;
+ int32 ix, res, olduse;
+
+/*
+ make sure c is big enough to hold a*b
+ */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow (c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ get the original destinations used count
+ */
+ olduse = c->used;
+
+/*
+ set the sign
+ */
+ c->sign = a->sign;
+
+/*
+ alias for a->dp [source]
+ */
+ tmpa = a->dp;
+
+/*
+ alias for c->dp [dest]
+ */
+ tmpc = c->dp;
+
+ /* zero carry */
+ u = 0;
+
+ /* compute columns */
+ for (ix = 0; ix < a->used; ix++) {
+/*
+ compute product and carry sum for this term
+ */
+ r = ((mp_word) u) + ((mp_word)*tmpa++) * ((mp_word)b);
+
+/*
+ mask off higher bits to get a single digit
+ */
+ *tmpc++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+/*
+ send carry into next iteration
+ */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+
+/*
+ store final carry [if any] and increment ix offset
+ */
+ *tmpc++ = u;
+ ++ix;
+
+/*
+ now zero digits above the top
+ */
+ while (ix++ < olduse) {
+ *tmpc++ = 0;
+ }
+
+ /* set used count */
+ c->used = a->used + 1;
+ mp_clamp(c);
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16
+ */
+#ifdef USE_SMALL_WORD
+int32 s_mp_sqr (psPool_t *pool, mp_int * a, mp_int * b)
+{
+ mp_int t;
+ int32 res, ix, iy, pa;
+ mp_word r;
+ mp_digit u, tmpx, *tmpt;
+
+ pa = a->used;
+ if ((res = mp_init_size(pool, &t, 2*pa + 1)) != MP_OKAY) {
+ return res;
+ }
+
+/*
+ default used is maximum possible size
+ */
+ t.used = 2*pa + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+/*
+ first calculate the digit at 2*ix
+ calculate double precision result
+ */
+ r = ((mp_word) t.dp[2*ix]) +
+ ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+/*
+ store lower part in result
+ */
+ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+/*
+ get the carry
+ */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+/*
+ left hand side of A[ix] * A[iy]
+ */
+ tmpx = a->dp[ix];
+
+/*
+ alias for where to store the results
+ */
+ tmpt = t.dp + (2*ix + 1);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+/*
+ first calculate the product
+ */
+ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+/*
+ now calculate the double precision result, note we use addition
+ instead of *2 since it's easier to optimize
+ */
+ r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+/*
+ store lower part
+ */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ /* propagate upwards */
+ while (u != ((mp_digit) 0)) {
+ r = ((mp_word) *tmpt) + ((mp_word) u);
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, b);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+#endif /* USE_SMALL_WORD */
+
+/******************************************************************************/
+/*
+ fast squaring
+
+ This is the comba method where the columns of the product are computed
+ first then the carries are computed. This has the effect of making a very
+ simple inner loop that is executed the most
+
+ W2 represents the outer products and W the inner.
+
+ A further optimizations is made because the inner products are of the
+ form "A * B * 2". The *2 part does not need to be computed until the end
+ which is good because 64-bit shifts are slow!
+
+ Based on Algorithm 14.16 on pp.597 of HAC.
+
+ This is the 1.0 version, but no SSE stuff
+*/
+int32 fast_s_mp_sqr(psPool_t *pool, mp_int * a, mp_int * b)
+{
+ int32 olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY], *tmpx;
+ mp_word W1;
+
+/*
+ grow the destination as required
+ */
+ pa = a->used + a->used;
+ if (b->alloc < pa) {
+ if ((res = mp_grow(b, pa)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ number of output digits to produce
+ */
+ W1 = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int32 tx, ty, iy;
+ mp_word _W;
+ mp_digit *tmpy;
+
+/*
+ clear counter
+ */
+ _W = 0;
+
+/*
+ get offsets into the two bignums
+ */
+ ty = MIN(a->used-1, ix);
+ tx = ix - ty;
+
+/*
+ setup temp aliases
+ */
+ tmpx = a->dp + tx;
+ tmpy = a->dp + ty;
+
+/*
+ this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+*/
+ iy = MIN(a->used-tx, ty+1);
+
+/*
+ now for squaring tx can never equal ty
+ we halve the distance since they approach at a rate of 2x
+ and we have to round because odd cases need to be executed
+*/
+ iy = MIN(iy, (ty-tx+1)>>1);
+
+/*
+ execute loop
+ */
+ for (iz = 0; iz < iy; iz++) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+ }
+
+/*
+ double the inner product and add carry
+ */
+ _W = _W + _W + W1;
+
+/*
+ even columns have the square term in them
+ */
+ if ((ix&1) == 0) {
+ _W += ((mp_word)a->dp[ix>>1])*((mp_word)a->dp[ix>>1]);
+ }
+
+/*
+ store it
+ */
+ W[ix] = (mp_digit)(_W & MP_MASK);
+
+/*
+ make next carry
+ */
+ W1 = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+/*
+ setup dest
+ */
+ olduse = b->used;
+ b->used = a->used+a->used;
+
+ {
+ mp_digit *tmpb;
+ tmpb = b->dp;
+ for (ix = 0; ix < pa; ix++) {
+ *tmpb++ = W[ix] & MP_MASK;
+ }
+
+/*
+ clear unused digits [that existed in the old copy of c]
+ */
+ for (; ix < olduse; ix++) {
+ *tmpb++ = 0;
+ }
+ }
+ mp_clamp(b);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ computes a = 2**b
+
+ Simple algorithm which zeroes the int32, grows it then just sets one bit
+ as required.
+ */
+int32 mp_2expt (mp_int * a, int32 b)
+{
+ int32 res;
+
+/*
+ zero a as per default
+ */
+ mp_zero (a);
+
+/*
+ grow a to accomodate the single bit
+ */
+ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+
+/*
+ set the used count of where the bit will go
+ */
+ a->used = b / DIGIT_BIT + 1;
+
+/*
+ put the single bit in its place
+ */
+ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ init an mp_init for a given size
+ */
+int32 mp_init_size(psPool_t *pool, mp_int * a, int32 size)
+{
+ int x;
+/*
+ pad size so there are always extra digits
+ */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+/*
+ alloc mem
+ */
+ a->dp = OPT_CAST(mp_digit) psMalloc(pool, sizeof (mp_digit) * size);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+/*
+ zero the digits
+ */
+ for (x = 0; x < size; x++) {
+ a->dp[x] = 0;
+ }
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ low level addition, based on HAC pp.594, Algorithm 14.7
+ */
+int32 s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int *x;
+ int32 olduse, res, min, max;
+
+/*
+ find sizes, we let |a| <= |b| which means we have to sort them. "x" will
+ point to the input with the most digits
+ */
+ if (a->used > b->used) {
+ min = b->used;
+ max = a->used;
+ x = a;
+ } else {
+ min = a->used;
+ max = b->used;
+ x = b;
+ }
+
+ /* init result */
+ if (c->alloc < max + 1) {
+ if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+/*
+ get old used digit count and set new one
+ */
+ olduse = c->used;
+ c->used = max + 1;
+
+ {
+ mp_digit u, *tmpa, *tmpb, *tmpc;
+ int32 i;
+
+ /* alias for digit pointers */
+
+ /* first input */
+ tmpa = a->dp;
+
+ /* second input */
+ tmpb = b->dp;
+
+ /* destination */
+ tmpc = c->dp;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+/*
+ Compute the sum at one digit, T[i] = A[i] + B[i] + U
+ */
+ *tmpc = *tmpa++ + *tmpb++ + u;
+
+/*
+ U = carry bit of T[i]
+ */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+/*
+ take away carry bit from T[i]
+ */
+ *tmpc++ &= MP_MASK;
+ }
+
+/*
+ now copy higher words if any, that is in A+B if A or B has more digits add
+ those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = X[i] + U */
+ *tmpc = x->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ *tmpc++ = u;
+
+/*
+ clear digits above oldused
+ */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+/******************************************************************************/
+/*
+ FUTURE - this is only needed by the SSH code, SLOW or not, because RSA
+ exponents are always odd.
+*/
+int32 mp_invmodSSH(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ int32 res;
+
+/*
+ b cannot be negative
+ */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+/*
+ if the modulus is odd we can use a faster routine instead
+ */
+ if (mp_isodd (b) == 1) {
+ return fast_mp_invmod(pool, a, b, c);
+ }
+
+/*
+ init temps
+ */
+ if ((res = _mp_init_multi(pool, &x, &y, &u, &v,
+ &A, &B, &C, &D)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x = a, y = b */
+ if ((res = mp_copy(a, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy(b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+/*
+ 2. [modified] if x,y are both even then return an error!
+ */
+ if (mp_iseven(&x) == 1 && mp_iseven (&y) == 1) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+/*
+ 3. u=x, v=y, A=1, B=0, C=0,D=1
+ */
+ if ((res = mp_copy(&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy(&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&A, 1);
+ mp_set (&D, 1);
+
+top:
+/*
+ 4. while u is even do
+ */
+ while (mp_iseven(&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2(&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if A or B is odd then */
+ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((res = mp_add(&A, &y, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub(&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* A = A/2, B = B/2 */
+ if ((res = mp_div_2(&A, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2(&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ 5. while v is even do
+ */
+ while (mp_iseven(&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2(&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if C or D is odd then */
+ if (mp_isodd(&C) == 1 || mp_isodd (&D) == 1) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((res = mp_add(&C, &y, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub(&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* C = C/2, D = D/2 */
+ if ((res = mp_div_2(&C, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2(&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ 6. if u >= v then
+ */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((res = mp_sub(&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&A, &C, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((res = mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&C, &A, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ if not zero goto step 4
+ */
+ if (mp_iszero(&u) == 0)
+ goto top;
+
+/*
+ now a = C, b = D, gcd == g*v
+ */
+
+/*
+ if v != 1 then there is no inverse
+ */
+ if (mp_cmp_d(&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+/*
+ if its too low
+ */
+ while (mp_cmp_d(&C, 0) == MP_LT) {
+ if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ too big
+ */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ C is now the inverse
+ */
+ mp_exch(&C, c);
+ res = MP_OKAY;
+LBL_ERR:_mp_clear_multi(&x, &y, &u, &v, &A, &B, &C, &D);
+ return res;
+}
+
+/******************************************************************************/
+
+/*
+ * Computes the modular inverse via binary extended euclidean algorithm,
+ * that is c = 1/a mod b
+ *
+ * Based on slow invmod except this is optimized for the case where b is
+ * odd as per HAC Note 14.64 on pp. 610
+ */
+int32 fast_mp_invmod(psPool_t *pool, mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, B, D;
+ int32 res, neg;
+
+/*
+ 2. [modified] b must be odd
+ */
+ if (mp_iseven (b) == 1) {
+ return MP_VAL;
+ }
+
+/*
+ init all our temps
+ */
+ if ((res = _mp_init_multi(pool, &x, &y, &u, &v, &B, &D, NULL, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+/*
+ x == modulus, y == value to invert
+ */
+ if ((res = mp_copy(b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+/*
+ we need y = |a|
+ */
+ if ((res = mp_mod(pool, a, b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+/*
+ 3. u=x, v=y, A=1, B=0, C=0,D=1
+ */
+ if ((res = mp_copy(&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy(&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set(&D, 1);
+
+top:
+/*
+ 4. while u is even do
+*/
+ while (mp_iseven(&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2(&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if B is odd then */
+ if (mp_isodd(&B) == 1) {
+ if ((res = mp_sub(&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* B = B/2 */
+ if ((res = mp_div_2(&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ 5. while v is even do
+ */
+ while (mp_iseven(&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2(&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if D is odd then */
+ if (mp_isodd(&D) == 1) {
+ /* D = (D-x)/2 */
+ if ((res = mp_sub(&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* D = D/2 */
+ if ((res = mp_div_2(&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ 6. if u >= v then
+ */
+ if (mp_cmp(&u, &v) != MP_LT) {
+ /* u = u - v, B = B - D */
+ if ((res = mp_sub(&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, D = D - B */
+ if ((res = mp_sub(&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub(&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+/*
+ if not zero goto step 4
+ */
+ if (mp_iszero(&u) == 0) {
+ goto top;
+ }
+
+/*
+ now a = C, b = D, gcd == g*v
+ */
+
+/*
+ if v != 1 then there is no inverse
+ */
+ if (mp_cmp_d(&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+/*
+ b is now the inverse
+ */
+ neg = a->sign;
+ while (D.sign == MP_NEG) {
+ if ((res = mp_add(&D, b, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ mp_exch(&D, c);
+ c->sign = neg;
+ res = MP_OKAY;
+
+LBL_ERR:_mp_clear_multi(&x, &y, &u, &v, &B, &D, NULL, NULL);
+ return res;
+}
+
+/******************************************************************************/
+/*
+ d = a + b (mod c)
+ */
+int32 mp_addmod (psPool_t *pool, mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int32 res;
+ mp_int t;
+
+ if ((res = mp_init(pool, &t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_add (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (pool, &t, c, d);
+ mp_clear (&t);
+ return res;
+}
+
+/******************************************************************************/
+/*
+ shrink a bignum
+ */
+int32 mp_shrink (mp_int * a)
+{
+ mp_digit *tmp;
+
+ if (a->alloc != a->used && a->used > 0) {
+ if ((tmp = psRealloc(a->dp, sizeof (mp_digit) * a->used)) == NULL) {
+ return MP_MEM;
+ }
+ a->dp = tmp;
+ a->alloc = a->used;
+ }
+ return MP_OKAY;
+}
+
+/* single digit subtraction */
+int32 mp_sub_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ mp_digit *tmpa, *tmpc, mu;
+ int32 res, ix, oldused;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative just do an unsigned
+ * addition [with fudged signs]
+ */
+ if (a->sign == MP_NEG) {
+ a->sign = MP_ZPOS;
+ res = mp_add_d(a, b, c);
+ a->sign = c->sign = MP_NEG;
+ return res;
+ }
+
+ /* setup regs */
+ oldused = c->used;
+ tmpa = a->dp;
+ tmpc = c->dp;
+
+ /* if a <= b simply fix the single digit */
+ if ((a->used == 1 && a->dp[0] <= b) || a->used == 0) {
+ if (a->used == 1) {
+ *tmpc++ = b - *tmpa;
+ } else {
+ *tmpc++ = b;
+ }
+ ix = 1;
+
+ /* negative/1digit */
+ c->sign = MP_NEG;
+ c->used = 1;
+ } else {
+ /* positive/size */
+ c->sign = MP_ZPOS;
+ c->used = a->used;
+
+ /* subtract first digit */
+ *tmpc = *tmpa++ - b;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+
+ /* handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ - mu;
+ mu = *tmpc >> (sizeof(mp_digit) * CHAR_BIT - 1);
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* zero excess digits */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+/* single digit addition */
+int32 mp_add_d (mp_int * a, mp_digit b, mp_int * c)
+{
+ int32 res, ix, oldused;
+ mp_digit *tmpa, *tmpc, mu;
+
+ /* grow c as required */
+ if (c->alloc < a->used + 1) {
+ if ((res = mp_grow(c, a->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* if a is negative and |a| >= b, call c = |a| - b */
+ if (a->sign == MP_NEG && (a->used > 1 || a->dp[0] >= b)) {
+ /* temporarily fix sign of a */
+ a->sign = MP_ZPOS;
+
+ /* c = |a| - b */
+ res = mp_sub_d(a, b, c);
+
+ /* fix sign */
+ a->sign = c->sign = MP_NEG;
+ return res;
+ }
+
+ /* old number of used digits in c */
+ oldused = c->used;
+
+ /* sign always positive */
+ c->sign = MP_ZPOS;
+
+ /* source alias */
+ tmpa = a->dp;
+
+ /* destination alias */
+ tmpc = c->dp;
+
+ /* if a is positive */
+ if (a->sign == MP_ZPOS) {
+ /* add digit, after this we're propagating the carry */
+ *tmpc = *tmpa++ + b;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+
+ /* now handle rest of the digits */
+ for (ix = 1; ix < a->used; ix++) {
+ *tmpc = *tmpa++ + mu;
+ mu = *tmpc >> DIGIT_BIT;
+ *tmpc++ &= MP_MASK;
+ }
+ /* set final carry */
+ ix++;
+ *tmpc++ = mu;
+
+ /* setup size */
+ c->used = a->used + 1;
+ } else {
+ /* a was negative and |a| < b */
+ c->used = 1;
+
+ /* the result is a single digit */
+ if (a->used == 1) {
+ *tmpc++ = b - a->dp[0];
+ } else {
+ *tmpc++ = b;
+ }
+
+ /* setup count so the clearing of oldused
+ * can fall through correctly
+ */
+ ix = 1;
+ }
+
+ /* now zero to oldused */
+ while (ix++ < oldused) {
+ *tmpc++ = 0;
+ }
+ mp_clamp(c);
+ return MP_OKAY;
+}
+
+
+/******************************************************************************/
+
+#endif /* USE_MPI2 */
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/mpi.h b/contrib/libs/matrixssl/src/crypto/peersec/mpi.h
new file mode 100644
index 00000000000..1b762877003
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/mpi.h
@@ -0,0 +1,476 @@
+/*
+ * mpi.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * multiple-precision integer library
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+
+#ifndef _h_MPI
+#define _h_MPI
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+
+#undef MIN
+#define MIN(x,y) ((x)<(y)?(x):(y))
+#undef MAX
+#define MAX(x,y) ((x)>(y)?(x):(y))
+
+#ifdef __cplusplus
+extern "C" {
+
+
+/*
+ C++ compilers don't like assigning void * to mp_digit *
+ */
+#define OPT_CAST(x) (x *)
+
+#else
+
+/*
+ C on the other hand doesn't care
+ */
+#define OPT_CAST(x)
+
+#endif /* __cplusplus */
+
+/******************************************************************************/
+/*
+ some default configurations.
+
+ A "mp_digit" must be able to hold DIGIT_BIT + 1 bits
+ A "mp_word" must be able to hold 2*DIGIT_BIT + 1 bits
+
+ At the very least a mp_digit must be able to hold 7 bits
+ [any size beyond that is ok provided it doesn't overflow the data type]
+ */
+#ifdef MP_8BIT
+ typedef unsigned char mp_digit;
+ typedef unsigned short mp_word;
+#elif defined(MP_16BIT)
+ typedef unsigned short mp_digit;
+ typedef unsigned long mp_word;
+#elif defined(MP_64BIT)
+/*
+ for GCC only on supported platforms
+ */
+ #ifndef CRYPT
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif /* CRYPT */
+
+ typedef ulong64 mp_digit;
+ typedef unsigned long mp_word __attribute__ ((mode(TI)));
+
+ #define DIGIT_BIT 60
+#else /* MP_8BIT */
+/*
+ this is the default case, 28-bit digits
+ */
+ #ifndef CRYPT
+ #if defined(_MSC_VER) || defined(__BORLANDC__)
+ typedef unsigned __int64 ulong64;
+ typedef signed __int64 long64;
+ #else
+ typedef unsigned long long ulong64;
+ typedef signed long long long64;
+ #endif
+ #endif /* CRYPT */
+
+ typedef unsigned long mp_digit;
+ typedef ulong64 mp_word;
+
+ #ifdef MP_31BIT
+/*
+ this is an extension that uses 31-bit digits
+ */
+ #define DIGIT_BIT 31
+ #else /* MP_31BIT */
+/*
+ default case is 28-bit digits, defines MP_28BIT as a handy macro to test
+ */
+ #define DIGIT_BIT 28
+ #define MP_28BIT
+ #endif /* MP_31BIT */
+#endif /* MP_8BIT */
+
+/*
+ otherwise the bits per digit is calculated automatically from the size of
+ a mp_digit
+ */
+#ifndef DIGIT_BIT
+ #define DIGIT_BIT ((int32)((CHAR_BIT * sizeof(mp_digit) - 1))) /* bits per digit */
+#endif /* DIGIT_BIT */
+
+#define MP_DIGIT_BIT DIGIT_BIT
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+#define MP_DIGIT_MAX MP_MASK
+
+/******************************************************************************/
+/*
+ equalities
+ */
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+#define MP_RANGE MP_VAL
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+typedef int32 mp_err;
+
+/******************************************************************************/
+/*
+ various build options
+ */
+#define MP_PREC 64 /* default digits of precision */
+
+/*
+ define this to use lower memory usage routines (exptmods mostly)
+ */
+#define MP_LOW_MEM
+
+/*
+ size of comba arrays, should be at least
+ 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2)
+ */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+typedef struct {
+ int32 used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+#define USED(m) ((m)->used)
+#define DIGIT(m,k) ((m)->dp[(k)])
+#define SIGN(m) ((m)->sign)
+
+/******************************************************************************/
+/*
+ init and deinit bignum functions
+ */
+
+/*
+ init a bignum
+ */
+extern int32 mp_init(psPool_t *pool, mp_int *a);
+
+/*
+ free a bignum
+ */
+extern void mp_clear(mp_int *a);
+
+/*
+ init a series of arguments
+ */
+extern int32 _mp_init_multi(psPool_t *pool, mp_int *mp0, mp_int *mp1, mp_int *mp2,
+ mp_int *mp3, mp_int *mp4, mp_int *mp5, mp_int *mp6,
+ mp_int *mp7);
+
+/*
+ clear a series of arguments
+ */
+extern void _mp_clear_multi(mp_int *mp0, mp_int *mp1, mp_int *mp2, mp_int *mp3,
+ mp_int *mp4, mp_int *mp5, mp_int *mp6, mp_int *mp7);
+
+/*
+ exchange two ints
+ */
+extern void mp_exch(mp_int *a, mp_int *b);
+
+/*
+ shrink ram required for a bignum
+ */
+extern int32 mp_shrink(mp_int *a);
+
+/*
+ grow an int32 to a given size
+ */
+extern int32 mp_grow(mp_int *a, int32 size);
+
+/*
+ init to a given number of digits
+ */
+extern int32 mp_init_size(psPool_t *pool, mp_int *a, int32 size);
+
+/******************************************************************************/
+/*
+ Basic Manipulations
+ */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+extern int32 mp_add_d (mp_int * a, mp_digit b, mp_int * c);
+extern int32 mp_sub_d (mp_int * a, mp_digit b, mp_int * c);
+/*
+ set to zero
+ */
+extern void mp_zero(mp_int *a);
+
+/*
+ set to a digit
+ */
+extern void mp_set(mp_int *a, mp_digit b);
+
+/*
+ copy, b = a
+ */
+extern int32 mp_copy(mp_int *a, mp_int *b);
+
+/*
+ inits and copies, a = b
+ */
+extern int32 mp_init_copy(psPool_t *pool, mp_int *a, mp_int *b);
+
+/*
+ trim unused digits
+ */
+extern void mp_clamp(mp_int *a);
+
+/******************************************************************************/
+/*
+ digit manipulation
+*/
+
+/*
+ right shift by "b" digits
+ */
+extern void mp_rshd(mp_int *a, int32 b);
+
+/*
+ left shift by "b" digits
+ */
+extern int32 mp_lshd(mp_int *a, int32 b);
+
+/*
+ c = a / 2**b
+ */
+extern int32 mp_div_2d(psPool_t *pool, mp_int *a, int32 b, mp_int *c, mp_int *d);
+
+/*
+ b = a/2
+ */
+extern int32 mp_div_2(mp_int *a, mp_int *b);
+
+/*
+ c = a * 2**b
+ */
+extern int32 mp_mul_2d(mp_int *a, int32 b, mp_int *c);
+
+/*
+ c = a mod 2**d
+ */
+extern int32 mp_mod_2d(mp_int *a, int32 b, mp_int *c);
+
+/*
+ computes a = 2**b
+ */
+extern int32 mp_2expt(mp_int *a, int32 b);
+
+/******************************************************************************/
+/*
+ Basic arithmetic
+ */
+
+/*
+ b = |a|
+ */
+extern int32 mp_abs(mp_int *a, mp_int *b);
+
+/*
+ compare a to b
+ */
+extern int32 mp_cmp(mp_int *a, mp_int *b);
+
+/*
+ compare |a| to |b|
+ */
+extern int32 mp_cmp_mag(mp_int *a, mp_int *b);
+
+/*
+ c = a + b
+ */
+extern int32 mp_add(mp_int *a, mp_int *b, mp_int *c);
+
+/*
+ c = a - b
+ */
+extern int32 mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+/*
+ c = a * b
+ b = a*a
+ */
+/* moved mp_mul out of SLOW case */
+extern int32 mp_mul(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+#ifdef USE_SMALL_WORD
+extern int32 mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+#endif
+
+/*
+ a/b => cb + d == a
+ */
+extern int32 mp_div(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ c = a mod b, 0 <= c < b
+ */
+extern int32 mp_mod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+
+/******************************************************************************/
+/*
+ single digit functions
+ */
+
+/*
+ compare against a single digit
+ */
+extern int32 mp_cmp_d(mp_int *a, mp_digit b);
+
+/*
+ c = a * b
+ */
+extern int32 mp_mul_d(mp_int *a, mp_digit b, mp_int *c);
+
+/******************************************************************************/
+/*
+ number theory
+ */
+
+/*
+ d = a + b (mod c)
+ */
+extern int32 mp_addmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ d = a * b (mod c)
+ */
+extern int32 mp_mulmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/*
+ c = 1/a (mod b)
+ */
+extern int32 mp_invmodSSH(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+
+/*
+ setups the montgomery reduction
+ */
+extern int32 mp_montgomery_setup(mp_int *a, mp_digit *mp);
+
+/*
+ computes a = B**n mod b without division or multiplication useful for
+ normalizing numbers in a Montgomery system.
+ */
+extern int32 mp_montgomery_calc_normalization(mp_int *a, mp_int *b);
+
+/*
+ computes x/R == x (mod N) via Montgomery Reduction
+ */
+#ifdef USE_SMALL_WORD
+extern int32 mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+#endif
+
+/*
+ d = a**b (mod c)
+ */
+extern int32 mp_exptmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c, mp_int *d);
+
+/******************************************************************************/
+/*
+ If we're using 1024 or 2048 bit keys and 28 bit digits, we only need the
+ fast_ versions of these functions, removing the others to save space.
+ Otherwise, we include the slow versions as well and which version to use
+ is done at runtime.
+*/
+#ifdef USE_SMALL_WORD
+extern int32 s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
+ int32 digs);
+extern int32 s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+
+#else
+#define mp_montgomery_reduce fast_mp_montgomery_reduce
+#define mp_sqr fast_s_mp_sqr
+#define s_mp_mul_digs fast_s_mp_mul_digs
+#endif
+
+#define mp_invmod fast_mp_invmod
+
+/******************************************************************************/
+/*
+ radix conversion
+ */
+extern int32 mp_count_bits(mp_int *a);
+
+extern int32 mp_unsigned_bin_size(mp_int *a);
+extern int32 mp_read_unsigned_bin(mp_int *a, unsigned char *b, int32 c);
+extern int32 mp_to_unsigned_bin(psPool_t *pool, mp_int *a, unsigned char *b);
+
+extern int32 mp_signed_bin_size(mp_int *a);
+
+/*
+ lowlevel functions, do not call!
+ */
+/* define this in all cases for now FUTURE*/
+#define s_mp_mul(P, A, B, C) s_mp_mul_digs(P, A, B, C, (A)->used + (B)->used + 1)
+
+
+/*
+ b = a*2
+ */
+extern int32 mp_mul_2(mp_int *a, mp_int *b);
+
+extern int32 s_mp_add(mp_int *a, mp_int *b, mp_int *c);
+extern int32 s_mp_sub(mp_int *a, mp_int *b, mp_int *c);
+
+extern int32 fast_s_mp_mul_digs(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c,
+ int32 digs);
+extern int32 fast_s_mp_sqr(psPool_t *pool, mp_int *a, mp_int *b);
+
+extern int32 fast_mp_invmod(psPool_t *pool, mp_int *a, mp_int *b, mp_int *c);
+extern int32 fast_mp_montgomery_reduce(mp_int *a, mp_int *m, mp_digit mp);
+
+extern void bn_reverse(unsigned char *s, int32 len);
+
+
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+
+#endif /* _h_MPI */
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/pscrypto.h b/contrib/libs/matrixssl/src/crypto/peersec/pscrypto.h
new file mode 100644
index 00000000000..14033762ca0
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/pscrypto.h
@@ -0,0 +1,586 @@
+/*
+ * pscrypto.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Internal definitions for PeerSec Networks MatrixSSL cryptography provider
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_PSCRYPTO
+#define _h_PSCRYPTO
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ PeerSec crypto-specific defines.
+ */
+#define SMALL_CODE
+#define CLEAN_STACK
+/*
+ If Native 64 bit integers are not supported, we must set the 16 bit flag
+ to produce 32 bit mp_words in mpi.h
+ We must also include the slow MPI functions because the fast ones only
+ work with larger (28 bit) digit sizes.
+*/
+#ifndef USE_INT64
+#define MP_16BIT
+#endif /* USE_INT64 */
+
+#define USE_SMALL_WORD // removing buggy optimization (fast methods only work with data <= MP_WARRAY, so, removing slow ones leads to array bounds corruption)
+
+/******************************************************************************/
+
+#ifdef USE_RSA
+
+#include "mpi.h"
+
+#ifndef _win_
+ #define _stat stat
+#endif
+
+/* this is the "32-bit at least" data type
+ * Re-define it to suit your platform but it must be at least 32-bits
+ */
+typedef unsigned long ulong32;
+
+/*
+ Primary RSA Key struct. Define here for crypto
+*/
+typedef struct {
+ mp_int e, d, N, qP, dP, dQ, p, q;
+ int32 size; /* Size of the key in bytes */
+ int32 optimized; /* 1 for optimized */
+} sslRsaKey_t;
+
+#endif /* USE_RSA */
+
+
+
+/*
+ * Private
+ */
+extern int32 ps_base64_decode(const unsigned char *in, uint32 len,
+ unsigned char *out, uint32 *outlen);
+
+/*
+ * Memory routines
+ */
+extern void psZeromem(void *dst, size_t len);
+extern void psBurnStack(unsigned long len);
+
+
+/* max size of either a cipher/hash block or symmetric key [largest of the two] */
+#define MAXBLOCKSIZE 24
+
+/* ch1-01-1 */
+/* error codes [will be expanded in future releases] */
+enum {
+ CRYPT_OK=0, /* Result OK */
+ CRYPT_ERROR, /* Generic Error */
+ CRYPT_NOP, /* Not a failure but no operation was performed */
+
+ CRYPT_INVALID_KEYSIZE, /* Invalid key size given */
+ CRYPT_INVALID_ROUNDS, /* Invalid number of rounds */
+ CRYPT_FAIL_TESTVECTOR, /* Algorithm failed test vectors */
+
+ CRYPT_BUFFER_OVERFLOW, /* Not enough space for output */
+ CRYPT_INVALID_PACKET, /* Invalid input packet given */
+
+ CRYPT_INVALID_PRNGSIZE, /* Invalid number of bits for a PRNG */
+ CRYPT_ERROR_READPRNG, /* Could not read enough from PRNG */
+
+ CRYPT_INVALID_CIPHER, /* Invalid cipher specified */
+ CRYPT_INVALID_HASH, /* Invalid hash specified */
+ CRYPT_INVALID_PRNG, /* Invalid PRNG specified */
+
+ CRYPT_MEM, /* Out of memory */
+
+ CRYPT_PK_TYPE_MISMATCH, /* Not equivalent types of PK keys */
+ CRYPT_PK_NOT_PRIVATE, /* Requires a private PK key */
+
+ CRYPT_INVALID_ARG, /* Generic invalid argument */
+ CRYPT_FILE_NOTFOUND, /* File Not Found */
+
+ CRYPT_PK_INVALID_TYPE, /* Invalid type of PK key */
+ CRYPT_PK_INVALID_SYSTEM, /* Invalid PK system specified */
+ CRYPT_PK_DUP, /* Duplicate key already in key ring */
+ CRYPT_PK_NOT_FOUND, /* Key not found in keyring */
+ CRYPT_PK_INVALID_SIZE, /* Invalid size input for PK parameters */
+
+ CRYPT_INVALID_PRIME_SIZE /* Invalid size of prime requested */
+};
+
+/******************************************************************************/
+/*
+ hash defines
+ */
+struct sha1_state {
+#ifdef USE_INT64
+ ulong64 length;
+#else
+ ulong32 lengthHi;
+ ulong32 lengthLo;
+#endif /* USE_INT64 */
+ ulong32 state[5], curlen;
+ unsigned char buf[64];
+};
+
+struct md5_state {
+#ifdef USE_INT64
+ ulong64 length;
+#else
+ ulong32 lengthHi;
+ ulong32 lengthLo;
+#endif /* USE_INT64 */
+ ulong32 state[4], curlen;
+ unsigned char buf[64];
+};
+
+#ifdef USE_MD2
+struct md2_state {
+ unsigned char chksum[16], X[48], buf[16];
+ unsigned long curlen;
+};
+#endif /* USE_MD2 */
+
+
+
+typedef union {
+ struct sha1_state sha1;
+ struct md5_state md5;
+#ifdef USE_MD2
+ struct md2_state md2;
+#endif /* USE_MD2 */
+} hash_state;
+
+typedef hash_state sslSha1Context_t;
+typedef hash_state sslMd5Context_t;
+#ifdef USE_MD2
+typedef hash_state sslMd2Context_t;
+#endif /* USE_MD2 */
+
+typedef struct {
+ unsigned char pad[64];
+ union {
+ sslMd5Context_t md5;
+ sslSha1Context_t sha1;
+ } u;
+} sslHmacContext_t;
+
+/******************************************************************************/
+/*
+ RC4
+ */
+#ifdef USE_ARC4
+typedef struct {
+ unsigned char state[256];
+ uint32 byteCount;
+ unsigned char x;
+ unsigned char y;
+} rc4_key;
+#endif /* USE_ARC4 */
+
+
+#define SSL_DES3_KEY_LEN 24
+#define SSL_DES3_IV_LEN 8
+#define SSL_DES_KEY_LEN 8
+
+#ifdef USE_3DES
+
+typedef struct {
+ ulong32 ek[3][32], dk[3][32];
+} des3_key;
+
+/*
+ A block cipher CBC structure
+ */
+typedef struct {
+ int32 blocklen;
+ unsigned char IV[8];
+ des3_key key;
+ int32 explicitIV; /* 1 if yes */
+} des3_CBC;
+
+extern int32 des3_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey);
+extern void des3_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key);
+extern void des3_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key);
+extern int32 des3_keysize(int32 *desired_keysize);
+
+extern int32 des_setup(const unsigned char *key, int32 keylen, int32 num_rounds,
+ des3_CBC *skey);
+extern void des_ecb_encrypt(const unsigned char *pt, unsigned char *ct,
+ des3_CBC *key);
+extern void des_ecb_decrypt(const unsigned char *ct, unsigned char *pt,
+ des3_CBC *key);
+
+#endif /* USE_3DES */
+
+
+
+typedef union {
+#ifdef USE_ARC4
+ rc4_key arc4;
+#endif
+#ifdef USE_3DES
+ des3_CBC des3;
+#endif
+} sslCipherContext_t;
+
+
+#if !(defined(_little_endian_) || defined(_big_endian_)) || !(defined(_32_) || defined(_64_))
+ #error You must specify a word size as well as endianess
+#endif
+
+/*
+ helper macros
+ */
+#ifdef _little_endian_
+
+#define STORE32H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>24)&255); (y)[1] = (unsigned char)(((x)>>16)&255); \
+ (y)[2] = (unsigned char)(((x)>>8)&255); (y)[3] = (unsigned char)((x)&255); }
+
+#define LOAD32H(x, y) \
+ { x = ((unsigned long)((y)[0] & 255)<<24) | \
+ ((unsigned long)((y)[1] & 255)<<16) | \
+ ((unsigned long)((y)[2] & 255)<<8) | \
+ ((unsigned long)((y)[3] & 255)); }
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48) | \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32) | \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16) | \
+ (((ulong64)((y)[6] & 255))<<8)|(((ulong64)((y)[7] & 255))); }
+
+#ifdef _32_
+
+#define STORE32L(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ memcpy(&(x), y, 4);
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48)| \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32)| \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16)| \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32L(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32L(x, y) \
+ { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64L(x, y) \
+ { ulong64 __t = (x); memcpy(y, &__t, 8); }
+
+#define LOAD64L(x, y) \
+ { memcpy(&(x), y, 8); }
+
+#endif /* _64_ */
+#endif /* _little_endian_ */
+
+#ifdef _big_endian_
+#define STORE32L(x, y) \
+ { (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD32L(x, y) \
+ { x = ((unsigned long)((y)[3] & 255)<<24) | \
+ ((unsigned long)((y)[2] & 255)<<16) | \
+ ((unsigned long)((y)[1] & 255)<<8) | \
+ ((unsigned long)((y)[0] & 255)); }
+
+#define STORE64L(x, y) \
+ { (y)[7] = (unsigned char)(((x)>>56)&255); (y)[6] = (unsigned char)(((x)>>48)&255); \
+ (y)[5] = (unsigned char)(((x)>>40)&255); (y)[4] = (unsigned char)(((x)>>32)&255); \
+ (y)[3] = (unsigned char)(((x)>>24)&255); (y)[2] = (unsigned char)(((x)>>16)&255); \
+ (y)[1] = (unsigned char)(((x)>>8)&255); (y)[0] = (unsigned char)((x)&255); }
+
+#define LOAD64L(x, y) \
+ { x = (((ulong64)((y)[7] & 255))<<56)|(((ulong64)((y)[6] & 255))<<48) | \
+ (((ulong64)((y)[5] & 255))<<40)|(((ulong64)((y)[4] & 255))<<32) | \
+ (((ulong64)((y)[3] & 255))<<24)|(((ulong64)((y)[2] & 255))<<16) | \
+ (((ulong64)((y)[1] & 255))<<8)|(((ulong64)((y)[0] & 255))); }
+
+#ifdef _32_
+
+#define STORE32H(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ memcpy(&(x), y, 4);
+
+#define STORE64H(x, y) \
+ { (y)[0] = (unsigned char)(((x)>>56)&255); (y)[1] = (unsigned char)(((x)>>48)&255); \
+ (y)[2] = (unsigned char)(((x)>>40)&255); (y)[3] = (unsigned char)(((x)>>32)&255); \
+ (y)[4] = (unsigned char)(((x)>>24)&255); (y)[5] = (unsigned char)(((x)>>16)&255); \
+ (y)[6] = (unsigned char)(((x)>>8)&255); (y)[7] = (unsigned char)((x)&255); }
+
+#define LOAD64H(x, y) \
+ { x = (((ulong64)((y)[0] & 255))<<56)|(((ulong64)((y)[1] & 255))<<48)| \
+ (((ulong64)((y)[2] & 255))<<40)|(((ulong64)((y)[3] & 255))<<32)| \
+ (((ulong64)((y)[4] & 255))<<24)|(((ulong64)((y)[5] & 255))<<16)| \
+ (((ulong64)((y)[6] & 255))<<8)| (((ulong64)((y)[7] & 255))); }
+
+#else /* 64-bit words then */
+
+#define STORE32H(x, y) \
+ { unsigned long __t = (x); memcpy(y, &__t, 4); }
+
+#define LOAD32H(x, y) \
+ { memcpy(&(x), y, 4); x &= 0xFFFFFFFF; }
+
+#define STORE64H(x, y) \
+ { ulong64 __t = (x); memcpy(y, &__t, 8); }
+
+#define LOAD64H(x, y) \
+ { memcpy(&(x), y, 8); }
+
+#endif /* _64_ */
+#endif /* _big_endian_ */
+
+/*
+ packet code */
+#if defined(USE_RSA) || defined(MDH) || defined(MECC)
+ #define PACKET
+
+/*
+ size of a packet header in bytes */
+ #define PACKET_SIZE 4
+
+/*
+ Section tags
+ */
+ #define PACKET_SECT_RSA 0
+ #define PACKET_SECT_DH 1
+ #define PACKET_SECT_ECC 2
+ #define PACKET_SECT_DSA 3
+
+/*
+ Subsection Tags for the first three sections
+ */
+ #define PACKET_SUB_KEY 0
+ #define PACKET_SUB_ENCRYPTED 1
+ #define PACKET_SUB_SIGNED 2
+ #define PACKET_SUB_ENC_KEY 3
+#endif
+
+/*
+ fix for MSVC ...evil!
+ */
+#ifdef _win_
+#ifdef _MSC_VER
+ #define CONST64(n) n ## ui64
+ typedef unsigned __int64 ulong64;
+#else
+ #define CONST64(n) n ## ULL
+ typedef unsigned long long ulong64;
+#endif
+#endif /* _win_ */
+
+
+#define BSWAP(x) ( ((x>>24)&0x000000FFUL) | ((x<<24)&0xFF000000UL) | \
+ ((x>>8)&0x0000FF00UL) | ((x<<8)&0x00FF0000UL) )
+
+#ifdef _MSC_VER
+
+/*
+ instrinsic rotate
+ */
+#include <stdlib.h>
+#pragma intrinsic(_lrotr,_lrotl)
+#define ROR(x,n) _lrotr(x,n)
+#define ROL(x,n) _lrotl(x,n)
+#define RORc(x,n) _lrotr(x,n)
+#define ROLc(x,n) _lrotl(x,n)
+
+/*
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) && !defined(PS_NO_ASM)
+
+static inline unsigned ROL(unsigned word, int32 i)
+{
+ asm ("roll %%cl,%0"
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned ROR(unsigned word, int32 i)
+{
+ asm ("rorl %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+*/
+/*
+#ifndef PS_NO_ROLC
+
+static inline unsigned ROLc(unsigned word, const int32 i)
+{
+ asm ("roll %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+static inline unsigned RORc(unsigned word, const int32 i)
+{
+ asm ("rorl %2,%0"
+ :"=r" (word)
+ :"0" (word),"I" (i));
+ return word;
+}
+
+#else
+
+#define ROLc ROL
+#define RORc ROR
+
+#endif
+*/
+
+#else /* _MSC_VER */
+
+/*
+ rotates the hard way
+ */
+#define ROL(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROR(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define ROLc(x, y) ( (((unsigned long)(x)<<(unsigned long)((y)&31)) | (((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL)
+
+#endif /* _MSC_VER */
+
+/* 64-bit Rotates */
+#if 0
+
+#if defined(__GNUC__) && defined(__x86_64__) && !defined(PS_NO_ASM)
+
+static inline unsigned long ROL64(unsigned long word, int32 i)
+{
+ asm("rolq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+static inline unsigned long ROR64(unsigned long word, int32 i)
+{
+ asm("rorq %%cl,%0"
+ :"=r" (word)
+ :"0" (word),"c" (i));
+ return word;
+}
+
+#ifndef PS_NO_ROLC
+
+static inline unsigned long ROL64c(unsigned long word, const int32 i)
+{
+ asm("rolq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+static inline unsigned long ROR64c(unsigned long word, const int32 i)
+{
+ asm("rorq %2,%0"
+ :"=r" (word)
+ :"0" (word),"J" (i));
+ return word;
+}
+
+#else /* PS_NO_ROLC */
+
+#define ROL64c ROL
+#define ROR64c ROR
+
+#endif /* PS_NO_ROLC */
+#endif
+#endif /* commented out */
+
+#define ROL64(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROL64c(x, y) \
+ ( (((x)<<((ulong64)(y)&63)) | \
+ (((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)64-((y)&63)))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#define ROR64c(x, y) \
+ ( ((((x)&CONST64(0xFFFFFFFFFFFFFFFF))>>((ulong64)(y)&CONST64(63))) | \
+ ((x)<<((ulong64)(64-((y)&CONST64(63)))))) & CONST64(0xFFFFFFFFFFFFFFFF))
+
+#undef MAX
+#undef MIN
+#define MAX(x, y) ( ((x)>(y))?(x):(y) )
+#define MIN(x, y) ( ((x)<(y))?(x):(y) )
+
+/*
+ extract a byte portably This MSC code causes runtime errors in VS.NET,
+ always use the other
+ */
+/*
+#ifdef _MSC_VER
+ #define byte(x, n) ((unsigned char)((x) >> (8 * (n))))
+#else
+*/
+ #define byte(x, n) (((x) >> (8 * (n))) & 255)
+/*
+#endif
+*/
+#ifdef __cplusplus
+ }
+#endif /* __cplusplus */
+
+#endif /* _h_PSCRYPTO */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/rsa.c b/contrib/libs/matrixssl/src/crypto/peersec/rsa.c
new file mode 100644
index 00000000000..116f48765b4
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/rsa.c
@@ -0,0 +1,463 @@
+/*
+ * rsa.c
+ * Release $Name: MATRIXSSL_1_8_7_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 */
+
+/******************************************************************************/
+
+
+
+
+
diff --git a/contrib/libs/matrixssl/src/crypto/peersec/sha1.c b/contrib/libs/matrixssl/src/crypto/peersec/sha1.c
new file mode 100644
index 00000000000..b1704ada8e9
--- /dev/null
+++ b/contrib/libs/matrixssl/src/crypto/peersec/sha1.c
@@ -0,0 +1,317 @@
+/*
+ * sha1.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * SHA1 hash implementation
+ */
+/*
+ * 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"
+
+#define F0(x,y,z) (z ^ (x & (y ^ z)))
+#define F1(x,y,z) (x ^ y ^ z)
+#define F2(x,y,z) ((x & y) | (z & (x | y)))
+#define F3(x,y,z) (x ^ y ^ z)
+
+#ifdef CLEAN_STACK
+static void _sha1_compress(hash_state *md)
+#else
+static void sha1_compress(hash_state *md)
+#endif /* CLEAN STACK */
+{
+ unsigned long a,b,c,d,e,W[80],i;
+#ifdef SMALL_CODE
+ ulong32 t;
+#endif
+
+ sslAssert(md != NULL);
+
+/*
+ copy the state into 512-bits into W[0..15]
+ */
+ for (i = 0; i < 16; i++) {
+ LOAD32H(W[i], md->sha1.buf + (4*i));
+ }
+
+/*
+ copy state
+ */
+ a = md->sha1.state[0];
+ b = md->sha1.state[1];
+ c = md->sha1.state[2];
+ d = md->sha1.state[3];
+ e = md->sha1.state[4];
+
+/*
+ expand it
+ */
+ for (i = 16; i < 80; i++) {
+ W[i] = ROL(W[i-3] ^ W[i-8] ^ W[i-14] ^ W[i-16], 1);
+ }
+
+/*
+ compress
+ */
+ /* round one */
+ #define FF0(a,b,c,d,e,i) e = (ROLc(a, 5) + F0(b,c,d) + e + W[i] + 0x5a827999UL); b = ROLc(b, 30);
+ #define FF1(a,b,c,d,e,i) e = (ROLc(a, 5) + F1(b,c,d) + e + W[i] + 0x6ed9eba1UL); b = ROLc(b, 30);
+ #define FF2(a,b,c,d,e,i) e = (ROLc(a, 5) + F2(b,c,d) + e + W[i] + 0x8f1bbcdcUL); b = ROLc(b, 30);
+ #define FF3(a,b,c,d,e,i) e = (ROLc(a, 5) + F3(b,c,d) + e + W[i] + 0xca62c1d6UL); b = ROLc(b, 30);
+
+#ifdef SMALL_CODE
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++); t = e; e = d; d = c; c = b; b = a; a = t;
+ }
+#else /* SMALL_CODE */
+ for (i = 0; i < 20; ) {
+ FF0(a,b,c,d,e,i++);
+ FF0(e,a,b,c,d,i++);
+ FF0(d,e,a,b,c,i++);
+ FF0(c,d,e,a,b,i++);
+ FF0(b,c,d,e,a,i++);
+ }
+
+ /* round two */
+ for (; i < 40; ) {
+ FF1(a,b,c,d,e,i++);
+ FF1(e,a,b,c,d,i++);
+ FF1(d,e,a,b,c,i++);
+ FF1(c,d,e,a,b,i++);
+ FF1(b,c,d,e,a,i++);
+ }
+
+ /* round three */
+ for (; i < 60; ) {
+ FF2(a,b,c,d,e,i++);
+ FF2(e,a,b,c,d,i++);
+ FF2(d,e,a,b,c,i++);
+ FF2(c,d,e,a,b,i++);
+ FF2(b,c,d,e,a,i++);
+ }
+
+ /* round four */
+ for (; i < 80; ) {
+ FF3(a,b,c,d,e,i++);
+ FF3(e,a,b,c,d,i++);
+ FF3(d,e,a,b,c,i++);
+ FF3(c,d,e,a,b,i++);
+ FF3(b,c,d,e,a,i++);
+ }
+#endif /* SMALL_CODE */
+
+ #undef FF0
+ #undef FF1
+ #undef FF2
+ #undef FF3
+
+/*
+ store
+ */
+ md->sha1.state[0] = md->sha1.state[0] + a;
+ md->sha1.state[1] = md->sha1.state[1] + b;
+ md->sha1.state[2] = md->sha1.state[2] + c;
+ md->sha1.state[3] = md->sha1.state[3] + d;
+ md->sha1.state[4] = md->sha1.state[4] + e;
+}
+
+#ifdef CLEAN_STACK
+static void sha1_compress(hash_state *md)
+{
+ _sha1_compress(md);
+ psBurnStack(sizeof(unsigned long) * 87);
+}
+#endif /* CLEAN_STACK */
+
+void matrixSha1Init(hash_state * md)
+{
+ sslAssert(md != NULL);
+ md->sha1.state[0] = 0x67452301UL;
+ md->sha1.state[1] = 0xefcdab89UL;
+ md->sha1.state[2] = 0x98badcfeUL;
+ md->sha1.state[3] = 0x10325476UL;
+ md->sha1.state[4] = 0xc3d2e1f0UL;
+ md->sha1.curlen = 0;
+#ifdef USE_INT64
+ md->sha1.length = 0;
+#else
+ md->sha1.lengthHi = 0;
+ md->sha1.lengthLo = 0;
+#endif /* USE_INT64 */
+}
+
+void matrixSha1Update(hash_state * md, const unsigned char *buf, unsigned long len)
+{
+ unsigned long n;
+
+ sslAssert(md != NULL);
+ sslAssert(buf != NULL);
+ while (len > 0) {
+ n = MIN(len, (64 - md->sha1.curlen));
+ memcpy(md->sha1.buf + md->sha1.curlen, buf, (size_t)n);
+ md->sha1.curlen += n;
+ buf += n;
+ len -= n;
+
+ /* is 64 bytes full? */
+ if (md->sha1.curlen == 64) {
+ sha1_compress(md);
+#ifdef USE_INT64
+ md->sha1.length += 512;
+#else
+ n = (md->sha1.lengthLo + 512) & 0xFFFFFFFFL;
+ if (n < md->sha1.lengthLo) {
+ md->sha1.lengthHi++;
+ }
+ md->sha1.lengthLo = n;
+#endif /* USE_INT64 */
+ md->sha1.curlen = 0;
+ }
+ }
+}
+
+int32 matrixSha1Final(hash_state * md, unsigned char *hash)
+{
+ int32 i;
+#ifndef USE_INT64
+ unsigned long n;
+#endif
+ sslAssert(md != NULL);
+ if (md->sha1.curlen >= sizeof(md->sha1.buf) || hash == NULL) {
+ return -1;
+ }
+
+/*
+ increase the length of the message
+ */
+#ifdef USE_INT64
+ md->sha1.length += md->sha1.curlen << 3;
+#else
+ n = (md->sha1.lengthLo + (md->sha1.curlen << 3)) & 0xFFFFFFFFL;
+ if (n < md->sha1.lengthLo) {
+ md->sha1.lengthHi++;
+ }
+ md->sha1.lengthHi += (md->sha1.curlen >> 29);
+ md->sha1.lengthLo = n;
+#endif /* USE_INT64 */
+
+/*
+ append the '1' bit
+ */
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0x80;
+
+/*
+ if the length is currently above 56 bytes we append zeros then compress.
+ Then we can fall back to padding zeros and length encoding like normal.
+ */
+ if (md->sha1.curlen > 56) {
+ while (md->sha1.curlen < 64) {
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+ }
+ sha1_compress(md);
+ md->sha1.curlen = 0;
+ }
+
+/*
+ pad upto 56 bytes of zeroes
+ */
+ while (md->sha1.curlen < 56) {
+ md->sha1.buf[md->sha1.curlen++] = (unsigned char)0;
+ }
+
+/*
+ store length
+ */
+#ifdef USE_INT64
+ STORE64H(md->sha1.length, md->sha1.buf+56);
+#else
+ STORE32H(md->sha1.lengthHi, md->sha1.buf+56);
+ STORE32H(md->sha1.lengthLo, md->sha1.buf+60);
+#endif /* USE_INT64 */
+ sha1_compress(md);
+
+/*
+ copy output
+ */
+ for (i = 0; i < 5; i++) {
+ STORE32H(md->sha1.state[i], hash+(4*i));
+ }
+#ifdef CLEAN_STACK
+ psZeromem(md, sizeof(hash_state));
+#endif /* CLEAN_STACK */
+ return 20;
+}
+
+#ifdef PEERSEC_TEST
+
+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;
+}
+#endif /* PEERSEC_TEST */
+
+
+/******************************************************************************/
+
diff --git a/contrib/libs/matrixssl/src/matrixConfig.h b/contrib/libs/matrixssl/src/matrixConfig.h
new file mode 100644
index 00000000000..b21a30c5b54
--- /dev/null
+++ b/contrib/libs/matrixssl/src/matrixConfig.h
@@ -0,0 +1,97 @@
+/*
+ * matrixConfig.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Configuration settings for building the MatrixSSL library.
+ * These options affect the size and algorithms present in the library.
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_MATRIXCONFIG
+#define _h_MATRIXCONFIG
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+/*
+ Define the number of sessions to cache here.
+ Minimum value is 1
+ Session caching provides such an increase in performance that it isn't
+ an option to disable.
+*/
+#define SSL_SESSION_TABLE_SIZE 32
+
+/******************************************************************************/
+/*
+ Define the following to enable various cipher suites
+ At least one of these must be defined. If multiple are defined,
+ the handshake will determine which is best for the connection.
+*/
+#define USE_SSL_RSA_WITH_RC4_128_MD5
+#define USE_SSL_RSA_WITH_RC4_128_SHA
+#define USE_SSL_RSA_WITH_3DES_EDE_CBC_SHA
+
+/******************************************************************************/
+/*
+ Support for encrypted private key files, using 3DES
+*/
+#define USE_ENCRYPTED_PRIVATE_KEYS
+
+/******************************************************************************/
+/*
+ Support for client side SSL
+*/
+#define USE_CLIENT_SIDE_SSL
+#define USE_SERVER_SIDE_SSL
+
+
+/******************************************************************************/
+/*
+ Use native 64 bit integers (long longs)
+*/
+#define USE_INT64
+
+/******************************************************************************/
+/*
+ Hi-res POSIX timer. Use rdtscll() for timing routines in linux.c
+*/
+/* #define USE_RDTSCLL_TIME */
+
+/******************************************************************************/
+/*
+ Support for file system.
+*/
+#define USE_FILE_SYSTEM
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MATRIXCONFIG */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/matrixInternal.h b/contrib/libs/matrixssl/src/matrixInternal.h
new file mode 100644
index 00000000000..97bdaa5f048
--- /dev/null
+++ b/contrib/libs/matrixssl/src/matrixInternal.h
@@ -0,0 +1,396 @@
+/*
+ * matrixInternal.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Internal header file used for the MatrixSSL implementation.
+ * Only modifiers of the library should be intersted in this file
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_MATRIXINTERNAL
+#define _h_MATRIXINTERNAL
+#define _h_EXPORT_SYMBOLS
+
+#include "../matrixCommon.h"
+
+/******************************************************************************/
+/*
+ Helpers
+*/
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif /* min */
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif /* max */
+
+/******************************************************************************/
+/*
+ At the highest SSL level. Must include the lower level PKI
+*/
+#include "pki/pkiInternal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+
+#ifdef _win_
+#define fcntl(A, B, C)
+#define MSG_NOSIGNAL 0
+#endif /* _win_ */
+
+#define SSL_FLAGS_READ_SECURE 0x2
+#define SSL_FLAGS_WRITE_SECURE 0x4
+#define SSL_FLAGS_PUBLIC_SECURE 0x8
+#define SSL_FLAGS_RESUMED 0x10
+#define SSL_FLAGS_CLOSED 0x20
+#define SSL_FLAGS_NEED_ENCODE 0x40
+#define SSL_FLAGS_ERROR 0x80
+
+#define SSL2_HEADER_LEN 2
+#define SSL3_HEADER_LEN 5
+#define SSL3_HANDSHAKE_HEADER_LEN 4
+
+/*
+ These are defines rather than enums because we want to store them as char,
+ not int32 (enum size)
+*/
+#define SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC 20
+#define SSL_RECORD_TYPE_ALERT 21
+#define SSL_RECORD_TYPE_HANDSHAKE 22
+#define SSL_RECORD_TYPE_APPLICATION_DATA 23
+
+#define SSL_HS_HELLO_REQUEST 0
+#define SSL_HS_CLIENT_HELLO 1
+#define SSL_HS_SERVER_HELLO 2
+#define SSL_HS_HELLO_VERIFY_REQUEST 3
+#define SSL_HS_CERTIFICATE 11
+#define SSL_HS_SERVER_KEY_EXCHANGE 12
+#define SSL_HS_CERTIFICATE_REQUEST 13
+#define SSL_HS_SERVER_HELLO_DONE 14
+#define SSL_HS_CERTIFICATE_VERIFY 15
+#define SSL_HS_CLIENT_KEY_EXCHANGE 16
+#define SSL_HS_FINISHED 20
+#define SSL_HS_DONE 255 /* Handshake complete (internal) */
+
+#define INIT_ENCRYPT_CIPHER 0
+#define INIT_DECRYPT_CIPHER 1
+
+#define RSA_SIGN 1
+
+/*
+ Additional ssl alert value, indicating no error has ocurred.
+*/
+#define SSL_ALERT_NONE 255 /* No error */
+
+#define SSL_HS_RANDOM_SIZE 32
+#define SSL_HS_RSA_PREMASTER_SIZE 48
+
+#define SSL2_MAJ_VER 2
+#define SSL3_MAJ_VER 3
+#define SSL3_MIN_VER 0
+#define TLS_MIN_VER 1
+
+
+
+/*
+ SSL cipher suite values
+*/
+#define SSL_NULL_WITH_NULL_NULL 0x0000
+#define SSL_RSA_WITH_NULL_MD5 0x0001
+#define SSL_RSA_WITH_NULL_SHA 0x0002
+#define SSL_RSA_WITH_RC4_128_MD5 0x0004
+#define SSL_RSA_WITH_RC4_128_SHA 0x0005
+#define SSL_RSA_WITH_3DES_EDE_CBC_SHA 0x000A
+
+/*
+ Maximum key block size for any defined cipher
+ This must be validated if new ciphers are added
+ Value is largest total among all cipher suites for
+ 2*macSize + 2*keySize + 2*ivSize
+*/
+#define SSL_MAX_KEY_BLOCK_SIZE 2*20 + 2*24 + 2*8
+
+/*
+ Master secret is 48 bytes, sessionId is 32 bytes max
+*/
+#define SSL_HS_MASTER_SIZE 48
+#define SSL_MAX_SESSION_ID_SIZE 32
+
+
+/*
+ Round up the given length to the correct length with SSLv3 padding
+*/
+#define sslRoundup018(LEN, BLOCKSIZE) \
+ BLOCKSIZE <= 1 ? BLOCKSIZE : (((LEN) + 8) & ~7)
+
+/******************************************************************************/
+/*
+ SSL record and session structures
+*/
+typedef struct {
+ unsigned short len;
+ unsigned char majVer;
+ unsigned char minVer;
+ unsigned char type;
+ unsigned char pad[3]; /* Padding for 64 bit compat */
+} sslRec_t;
+
+typedef struct {
+ unsigned char clientRandom[SSL_HS_RANDOM_SIZE]; /* From ClientHello */
+ unsigned char serverRandom[SSL_HS_RANDOM_SIZE]; /* From ServerHello */
+ unsigned char masterSecret[SSL_HS_MASTER_SIZE];
+ unsigned char *premaster; /* variable size */
+ int32 premasterSize;
+
+ unsigned char keyBlock[SSL_MAX_KEY_BLOCK_SIZE]; /* Storage for the next six items */
+ unsigned char *wMACptr;
+ unsigned char *rMACptr;
+ unsigned char *wKeyptr;
+ unsigned char *rKeyptr;
+ unsigned char *wIVptr;
+ unsigned char *rIVptr;
+
+ /* All maximum sizes for current cipher suites */
+ unsigned char writeMAC[SSL_MAX_MAC_SIZE];
+ unsigned char readMAC[SSL_MAX_MAC_SIZE];
+ unsigned char writeKey[SSL_MAX_SYM_KEY_SIZE];
+ unsigned char readKey[SSL_MAX_SYM_KEY_SIZE];
+ unsigned char writeIV[SSL_MAX_IV_SIZE];
+ unsigned char readIV[SSL_MAX_IV_SIZE];
+
+ unsigned char seq[8];
+ unsigned char remSeq[8];
+
+#ifdef USE_CLIENT_SIDE_SSL
+ sslCert_t *cert;
+ int32 (*validateCert)(sslCertInfo_t *certInfo, void *arg);
+ void *validateCertArg;
+ int32 certMatch;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ sslMd5Context_t msgHashMd5;
+ sslSha1Context_t msgHashSha1;
+
+ sslCipherContext_t encryptCtx;
+ sslCipherContext_t decryptCtx;
+ int32 anon;
+} sslSec_t;
+
+typedef struct {
+ uint32 id;
+ unsigned char macSize;
+ unsigned char keySize;
+ unsigned char ivSize;
+ unsigned char blockSize;
+ /* Init function */
+ int32 (*init)(sslSec_t *sec, int32 type);
+ /* Cipher functions */
+ int32 (*encrypt)(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+ int32 (*decrypt)(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+ int32 (*encryptPriv)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*decryptPub)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*encryptPub)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*decryptPriv)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+ int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+} sslCipherSpec_t;
+
+typedef struct ssl {
+ sslRec_t rec; /* Current SSL record information*/
+
+ sslSec_t sec; /* Security structure */
+
+ sslKeys_t *keys; /* SSL public and private keys */
+
+ psPool_t *pool; /* SSL session pool */
+ psPool_t *hsPool; /* Full session handshake pool */
+
+ unsigned char sessionIdLen;
+ char sessionId[SSL_MAX_SESSION_ID_SIZE];
+
+ /* Pointer to the negotiated cipher information */
+ sslCipherSpec_t *cipher;
+
+ /* Symmetric cipher callbacks
+
+ We duplicate these here from 'cipher' because we need to set the
+ various callbacks at different times in the handshake protocol
+ Also, there are 64 bit alignment issues in using the function pointers
+ within 'cipher' directly
+ */
+ int32 (*encrypt)(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+ int32 (*decrypt)(sslCipherContext_t *ctx, unsigned char *in,
+ unsigned char *out, int32 len);
+ /* Public key ciphers */
+ int32 (*encryptPriv)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*decryptPub)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*encryptPub)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ int32 (*decryptPriv)(psPool_t *pool, sslRsaKey_t *key,
+ unsigned char *in, int32 inlen,
+ unsigned char *out, int32 outlen);
+ /* Message Authentication Codes */
+ int32 (*generateMac)(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+ int32 (*verifyMac)(void *ssl, unsigned char type, unsigned char *data,
+ int32 len, unsigned char *mac);
+
+ /* Current encryption/decryption parameters */
+ unsigned char enMacSize;
+ unsigned char enIvSize;
+ unsigned char enBlockSize;
+ unsigned char deMacSize;
+ unsigned char deIvSize;
+ unsigned char deBlockSize;
+
+ int32 flags;
+ int32 hsState; /* Next expected handshake message type */
+ int32 err; /* SSL errno of last api call */
+ int32 ignoredMessageCount;
+
+ unsigned char reqMajVer;
+ unsigned char reqMinVer;
+ unsigned char majVer;
+ unsigned char minVer;
+ int32 recordHeadLen;
+ int32 hshakeHeadLen;
+} ssl_t;
+
+typedef struct {
+ unsigned char id[SSL_MAX_SESSION_ID_SIZE];
+ unsigned char masterSecret[SSL_HS_MASTER_SIZE];
+ uint32 cipherId;
+} sslSessionId_t;
+
+typedef struct {
+ unsigned char id[SSL_MAX_SESSION_ID_SIZE];
+ unsigned char masterSecret[SSL_HS_MASTER_SIZE];
+ sslCipherSpec_t *cipher;
+ unsigned char majVer;
+ unsigned char minVer;
+ char flag;
+ sslTime_t startTime;
+ sslTime_t accessTime;
+ int32 inUse;
+} sslSessionEntry_t;
+
+/******************************************************************************/
+/*
+ Have ssl_t and sslSessionId_t now for addition of the public api set
+*/
+#include "../matrixSsl.h"
+
+/******************************************************************************/
+/*
+ sslEncode.c and sslDecode.c
+*/
+extern int32 psWriteRecordInfo(ssl_t *ssl, unsigned char type, int32 len,
+ unsigned char *c);
+extern int32 psWriteHandshakeHeader(ssl_t *ssl, unsigned char type, int32 len,
+ int32 seq, int32 fragOffset, int32 fragLen,
+ unsigned char *c);
+extern int32 sslEncodeResponse(ssl_t *ssl, sslBuf_t *out);
+extern int32 sslActivateReadCipher(ssl_t *ssl);
+extern int32 sslActivateWriteCipher(ssl_t *ssl);
+extern int32 sslActivatePublicCipher(ssl_t *ssl);
+extern int32 sslUpdateHSHash(ssl_t *ssl, unsigned char *in, int32 len);
+extern int32 sslInitHSHash(ssl_t *ssl);
+extern int32 sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag);
+extern int32 sslWritePad(unsigned char *p, unsigned char padLen);
+extern void sslResetContext(ssl_t *ssl);
+
+#ifdef USE_SERVER_SIDE_SSL
+extern int32 matrixRegisterSession(ssl_t *ssl);
+extern int32 matrixResumeSession(ssl_t *ssl);
+extern int32 matrixClearSession(ssl_t *ssl, int32 remove);
+extern int32 matrixUpdateSession(ssl_t *ssl);
+#endif /* USE_SERVER_SIDE_SSL */
+
+
+/*
+ cipherSuite.c
+*/
+extern sslCipherSpec_t *sslGetCipherSpec(int32 id);
+extern int32 sslGetCipherSpecListLen(void);
+extern int32 sslGetCipherSpecList(unsigned char *c, int32 len);
+
+/******************************************************************************/
+/*
+ sslv3.c
+*/
+extern int32 sslGenerateFinishedHash(sslMd5Context_t *md5, sslSha1Context_t *sha1,
+ unsigned char *masterSecret,
+ unsigned char *out, int32 sender);
+
+extern int32 sslDeriveKeys(ssl_t *ssl);
+
+#ifdef USE_SHA1_MAC
+extern int32 ssl3HMACSha1(unsigned char *key, unsigned char *seq,
+ unsigned char type, unsigned char *data, int32 len,
+ unsigned char *mac);
+#endif /* USE_SHA1_MAC */
+
+#ifdef USE_MD5_MAC
+extern int32 ssl3HMACMd5(unsigned char *key, unsigned char *seq,
+ unsigned char type, unsigned char *data, int32 len,
+ unsigned char *mac);
+#endif /* USE_MD5_MAC */
+
+
+
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MATRIXINTERNAL */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/matrixSsl.c b/contrib/libs/matrixssl/src/matrixSsl.c
new file mode 100644
index 00000000000..8c89a77db2e
--- /dev/null
+++ b/contrib/libs/matrixssl/src/matrixSsl.c
@@ -0,0 +1,803 @@
+/*
+ * matrixSsl.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Secure Sockets Layer session management
+ */
+/*
+ * 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 "matrixInternal.h"
+
+#include <time.h>
+
+/******************************************************************************/
+
+static char copyright[]= "Copyright PeerSec Networks Inc. All rights reserved.";
+
+#ifdef USE_SERVER_SIDE_SSL
+/*
+ Static session table for session cache and lock for multithreaded env
+*/
+static sslMutex_t sessionTableLock;
+static sslSessionEntry_t sessionTable[SSL_SESSION_TABLE_SIZE];
+#endif /* USE_SERVER_SIDE_SSL */
+
+/******************************************************************************/
+/*
+ Open and close the SSL module. These routines are called once in the
+ lifetime of the application and initialize and clean up the library
+ respectively.
+*/
+int32 matrixSslOpen(void)
+{
+ if (matrixPkiOpen() < 0) {
+ matrixStrDebugMsg("PKI open failure\n", NULL);
+ return -1;
+ }
+
+#ifdef USE_SERVER_SIDE_SSL
+ memset(sessionTable, 0x0,
+ sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE);
+ sslCreateMutex(&sessionTableLock);
+#endif /* USE_SERVER_SIDE_SSL */
+
+
+ return 0;
+}
+
+void matrixSslClose(void)
+{
+#ifdef USE_SERVER_SIDE_SSL
+ int32 i;
+
+ sslLockMutex(&sessionTableLock);
+ for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) {
+ if (sessionTable[i].inUse == 1) {
+ matrixStrDebugMsg("Warning: closing while session still in use\n",
+ NULL);
+ }
+ }
+ memset(sessionTable, 0x0,
+ sizeof(sslSessionEntry_t) * SSL_SESSION_TABLE_SIZE);
+ sslUnlockMutex(&sessionTableLock);
+ sslDestroyMutex(&sessionTableLock);
+#endif /* USE_SERVER_SIDE_SSL */
+
+
+ matrixPkiClose();
+}
+
+/******************************************************************************/
+/*
+ Wrappers around the RSA versions. Necessary to keep API backwards compat
+*/
+#ifdef USE_FILE_SYSTEM
+int32 matrixSslReadKeys(sslKeys_t **keys, const char *certFile,
+ const char *privFile, const char *privPass,
+ const char *trustedCAFile)
+{
+ return matrixX509ReadKeys(keys, certFile, privFile, privPass, trustedCAFile);
+}
+#endif /* USE_FILE_SYSTEM */
+
+int32 matrixSslReadKeysMem(sslKeys_t **keys, unsigned char *certBuf,
+ int32 certLen, unsigned char *privBuf, int32 privLen,
+ unsigned char *trustedCABuf, int32 trustedCALen)
+{
+ return matrixX509ReadKeysMem(keys, certBuf, certLen, privBuf, privLen,
+ trustedCABuf, trustedCALen);
+}
+
+void matrixSslFreeKeys(sslKeys_t *keys)
+{
+ matrixRsaFreeKeys(keys);
+}
+
+
+
+/******************************************************************************/
+/*
+ New SSL protocol context
+ This structure is associated with a single SSL connection. Each socket
+ using SSL should be associated with a new SSL context.
+
+ certBuf and privKey ARE NOT duplicated within the server context, in order
+ to minimize memory usage with multiple simultaneous requests. They must
+ not be deleted by caller until all server contexts using them are deleted.
+*/
+int32 matrixSslNewSession(ssl_t **ssl, sslKeys_t *keys, sslSessionId_t *session,
+ int32 flags)
+{
+ psPool_t *pool = NULL;
+ ssl_t *lssl;
+
+/*
+ First API level chance to make sure a user is not attempting to use
+ client or server support that was not built into this library compile
+*/
+#ifndef USE_SERVER_SIDE_SSL
+ if (flags & SSL_FLAGS_SERVER) {
+ matrixStrDebugMsg("MatrixSSL lib not compiled with server support\n",
+ NULL);
+ return -1;
+ }
+#endif
+#ifndef USE_CLIENT_SIDE_SSL
+ if (!(flags & SSL_FLAGS_SERVER)) {
+ matrixStrDebugMsg("MatrixSSL lib not compiled with client support\n",
+ NULL);
+ return -1;
+ }
+#endif
+ if (flags & SSL_FLAGS_CLIENT_AUTH) {
+ matrixStrDebugMsg("MatrixSSL lib not compiled with client " \
+ "authentication support\n", NULL);
+ return -1;
+ }
+
+ if (flags & SSL_FLAGS_SERVER) {
+ if (keys == NULL) {
+ matrixStrDebugMsg("NULL keys in matrixSslNewSession\n", NULL);
+ return -1;
+ }
+ if (session != NULL) {
+ matrixStrDebugMsg("Server session must be NULL\n", NULL);
+ return -1;
+ }
+ }
+
+ *ssl = lssl = psMalloc(pool, sizeof(ssl_t));
+ if (lssl == NULL) {
+ return SSL_MEM_ERROR;
+ }
+ memset(lssl, 0x0, sizeof(ssl_t));
+
+ lssl->pool = pool;
+ lssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL);
+ sslActivateReadCipher(lssl);
+ sslActivateWriteCipher(lssl);
+ sslActivatePublicCipher(lssl);
+
+ lssl->recordHeadLen = SSL3_HEADER_LEN;
+ lssl->hshakeHeadLen = SSL3_HANDSHAKE_HEADER_LEN;
+
+ if (flags & SSL_FLAGS_SERVER) {
+ lssl->flags |= SSL_FLAGS_SERVER;
+/*
+ Client auth can only be requested by server, not set by client
+*/
+ if (flags & SSL_FLAGS_CLIENT_AUTH) {
+ lssl->flags |= SSL_FLAGS_CLIENT_AUTH;
+ }
+ lssl->hsState = SSL_HS_CLIENT_HELLO;
+ } else {
+/*
+ Client is first to set protocol version information based on
+ compile and/or the 'flags' parameter so header information in
+ the handshake messages will be correctly set.
+*/
+ lssl->majVer = SSL3_MAJ_VER;
+ lssl->minVer = SSL3_MIN_VER;
+ lssl->hsState = SSL_HS_SERVER_HELLO;
+ if (session != NULL && session->cipherId != SSL_NULL_WITH_NULL_NULL) {
+ lssl->cipher = sslGetCipherSpec(session->cipherId);
+ if (lssl->cipher == NULL) {
+ matrixStrDebugMsg("Invalid session id to matrixSslNewSession\n",
+ NULL);
+ } else {
+ memcpy(lssl->sec.masterSecret, session->masterSecret,
+ SSL_HS_MASTER_SIZE);
+ lssl->sessionIdLen = SSL_MAX_SESSION_ID_SIZE;
+ memcpy(lssl->sessionId, session->id, SSL_MAX_SESSION_ID_SIZE);
+ }
+ }
+ }
+ lssl->err = SSL_ALERT_NONE;
+ lssl->keys = keys;
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Delete an SSL session. Some information on the session may stay around
+ in the session resumption cache.
+ SECURITY - We memset relevant values to zero before freeing to reduce
+ the risk of our keys floating around in memory after we're done.
+*/
+void matrixSslDeleteSession(ssl_t *ssl)
+{
+
+ if (ssl == NULL) {
+ return;
+ }
+ ssl->flags |= SSL_FLAGS_CLOSED;
+/*
+ If we have a sessionId, for servers we need to clear the inUse flag in
+ the session cache so the ID can be replaced if needed. In the client case
+ the caller should have called matrixSslGetSessionId already to copy the
+ master secret and sessionId, so free it now.
+
+ In all cases except a successful updateSession call on the server, the
+ master secret must be freed.
+*/
+#ifdef USE_SERVER_SIDE_SSL
+ if (ssl->sessionIdLen > 0 && (ssl->flags & SSL_FLAGS_SERVER)) {
+ matrixUpdateSession(ssl);
+ }
+#endif /* USE_SERVER_SIDE_SSL */
+ ssl->sessionIdLen = 0;
+
+#ifdef USE_CLIENT_SIDE_SSL
+ if (ssl->sec.cert) {
+ matrixX509FreeCert(ssl->sec.cert);
+ ssl->sec.cert = NULL;
+ }
+#endif /* USE_CLIENT_SIDE_SSL */
+
+/*
+ Premaster could also be allocated if this DeleteSession is the result
+ of a failed handshake. This test is fine since all frees will NULL pointer
+*/
+ if (ssl->sec.premaster) {
+ psFree(ssl->sec.premaster);
+ }
+
+
+
+/*
+ The cipher and mac contexts are inline in the ssl structure, so
+ clearing the structure clears those states as well.
+*/
+ memset(ssl, 0x0, sizeof(ssl_t));
+ psFree(ssl);
+}
+
+/******************************************************************************/
+/*
+ Generic session option control for changing already connected sessions.
+ (ie. rehandshake control). arg param is future for options that may
+ require a value.
+*/
+void matrixSslSetSessionOption(ssl_t *ssl, int32 option, void *arg)
+{
+ if (option == SSL_OPTION_DELETE_SESSION) {
+#ifdef USE_SERVER_SIDE_SSL
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+ matrixClearSession(ssl, 1);
+ }
+#endif /* USE_SERVER_SIDE_SSL */
+ ssl->sessionIdLen = 0;
+ memset(ssl->sessionId, 0x0, SSL_MAX_SESSION_ID_SIZE);
+ }
+}
+
+/******************************************************************************/
+/*
+ The ssl_t struct is opaque to the socket layer. Just needed an access
+ routine for the 'anon' status
+*/
+void matrixSslGetAnonStatus(ssl_t *ssl, int32 *certArg)
+{
+ *certArg = ssl->sec.anon;
+}
+
+/******************************************************************************/
+/*
+ Again, the ssl_t is opaque. Need to associate the new keys with
+ the session for mid-session rekeying
+*/
+void matrixSslAssignNewKeys(ssl_t *ssl, sslKeys_t *keys)
+{
+ ssl->keys = keys;
+}
+
+/******************************************************************************/
+/*
+ Returns 1 if we've completed the SSL handshake. 0 if we're in process.
+*/
+int32 matrixSslHandshakeIsComplete(ssl_t *ssl)
+{
+ return (ssl->hsState == SSL_HS_DONE) ? 1 : 0;
+}
+
+#ifdef USE_CLIENT_SIDE_SSL
+/******************************************************************************/
+/*
+ Set a custom callback to receive the certificate being presented to the
+ session to perform custom authentication if needed
+*/
+void matrixSslSetCertValidator(ssl_t *ssl,
+ int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg)
+{
+ if (certValidator) {
+ ssl->sec.validateCert = certValidator;
+ ssl->sec.validateCertArg = arg;
+ }
+}
+#else /* Public API, so should always be linkable */
+void matrixSslSetCertValidator(ssl_t *ssl,
+ int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg)
+{
+ matrixStrDebugMsg("matrixSslSetCertValidator is not available\n", NULL);
+ matrixStrDebugMsg("Library not built for cert validation support\n", NULL);
+}
+#endif /* USE_CLIENT_SIDE_SSL */
+
+/******************************************************************************/
+/*
+ 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;
+}
+
+/******************************************************************************/
+/*
+ Add the given data to the running hash of the handshake messages
+*/
+int32 sslUpdateHSHash(ssl_t *ssl, unsigned char *in, int32 len)
+{
+ matrixMd5Update(&ssl->sec.msgHashMd5, in, len);
+ matrixSha1Update(&ssl->sec.msgHashSha1, in, len);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Snapshot is called by the receiver of the finished message to produce
+ a hash of the preceeding handshake messages for comparison to incoming
+ message.
+*/
+int32 sslSnapshotHSHash(ssl_t *ssl, unsigned char *out, int32 senderFlag)
+{
+ sslMd5Context_t md5;
+ sslSha1Context_t sha1;
+
+/*
+ Use a backup of the message hash-to-date because we don't want
+ to destroy the state of the handshaking until truly complete
+*/
+ md5 = ssl->sec.msgHashMd5;
+ sha1 = ssl->sec.msgHashSha1;
+
+ return sslGenerateFinishedHash(&md5, &sha1, ssl->sec.masterSecret,
+ out, senderFlag);
+}
+
+/******************************************************************************/
+/*
+ Cipher suites are chosen before they are activated with the
+ ChangeCipherSuite message. Additionally, the read and write cipher suites
+ are activated at different times in the handshake process. The following
+ APIs activate the selected cipher suite callback functions.
+*/
+int32 sslActivateReadCipher(ssl_t *ssl)
+{
+ ssl->decrypt = ssl->cipher->decrypt;
+ ssl->verifyMac = ssl->cipher->verifyMac;
+ ssl->deMacSize = ssl->cipher->macSize;
+ ssl->deBlockSize = ssl->cipher->blockSize;
+ ssl->deIvSize = ssl->cipher->ivSize;
+/*
+ Reset the expected incoming sequence number for the new suite
+*/
+ memset(ssl->sec.remSeq, 0x0, sizeof(ssl->sec.remSeq));
+
+ if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) {
+ ssl->flags |= SSL_FLAGS_READ_SECURE;
+/*
+ Copy the newly activated read keys into the live buffers
+*/
+ memcpy(ssl->sec.readMAC, ssl->sec.rMACptr, ssl->cipher->macSize);
+ memcpy(ssl->sec.readKey, ssl->sec.rKeyptr, ssl->cipher->keySize);
+ memcpy(ssl->sec.readIV, ssl->sec.rIVptr, ssl->cipher->ivSize);
+/*
+ set up decrypt contexts
+ */
+ if (ssl->cipher->init(&(ssl->sec), INIT_DECRYPT_CIPHER) < 0) {
+ matrixStrDebugMsg("Unable to initialize read cipher suite\n", NULL);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int32 sslActivateWriteCipher(ssl_t *ssl)
+{
+
+ ssl->encrypt = ssl->cipher->encrypt;
+ ssl->generateMac = ssl->cipher->generateMac;
+ ssl->enMacSize = ssl->cipher->macSize;
+ ssl->enBlockSize = ssl->cipher->blockSize;
+ ssl->enIvSize = ssl->cipher->ivSize;
+/*
+ Reset the outgoing sequence number for the new suite
+*/
+ memset(ssl->sec.seq, 0x0, sizeof(ssl->sec.seq));
+ if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) {
+ ssl->flags |= SSL_FLAGS_WRITE_SECURE;
+/*
+ Copy the newly activated write keys into the live buffers
+*/
+ memcpy(ssl->sec.writeMAC, ssl->sec.wMACptr, ssl->cipher->macSize);
+ memcpy(ssl->sec.writeKey, ssl->sec.wKeyptr, ssl->cipher->keySize);
+ memcpy(ssl->sec.writeIV, ssl->sec.wIVptr, ssl->cipher->ivSize);
+/*
+ set up encrypt contexts
+ */
+ if (ssl->cipher->init(&(ssl->sec), INIT_ENCRYPT_CIPHER) < 0) {
+ matrixStrDebugMsg("Unable to init write cipher suite\n", NULL);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int32 sslActivatePublicCipher(ssl_t *ssl)
+{
+ ssl->encryptPriv = ssl->cipher->encryptPriv;
+ ssl->decryptPub = ssl->cipher->decryptPub;
+ ssl->decryptPriv = ssl->cipher->decryptPriv;
+ ssl->encryptPub = ssl->cipher->encryptPub;
+ if (ssl->cipher->id != SSL_NULL_WITH_NULL_NULL) {
+ ssl->flags |= SSL_FLAGS_PUBLIC_SECURE;
+ }
+ return 0;
+}
+
+#ifdef USE_SERVER_SIDE_SSL
+/******************************************************************************/
+/*
+ Register a session in the session resumption cache. If successful (rc >=0),
+ the ssl sessionId and sessionIdLength fields will be non-NULL upon
+ return.
+*/
+int32 matrixRegisterSession(ssl_t *ssl)
+{
+ uint32 i, j;
+ sslTime_t t;
+
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ return -1;
+ }
+/*
+ Iterate the session table, looking for an empty entry (cipher null), and
+ the oldest entry that is not in use
+*/
+ sslLockMutex(&sessionTableLock);
+ j = SSL_SESSION_TABLE_SIZE;
+ t = sessionTable[0].accessTime;
+ for (i = 0; i < SSL_SESSION_TABLE_SIZE; i++) {
+ if (sessionTable[i].cipher == NULL) {
+ break;
+ }
+ if (sslCompareTime(sessionTable[i].accessTime, t) &&
+ sessionTable[i].inUse == 0) {
+ t = sessionTable[i].accessTime;
+ j = i;
+ }
+ }
+/*
+ If there were no empty entries, get the oldest unused entry.
+ If all entries are in use, return -1, meaning we can't cache the
+ session at this time
+*/
+ if (i >= SSL_SESSION_TABLE_SIZE) {
+ if (j < SSL_SESSION_TABLE_SIZE) {
+ i = j;
+ } else {
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+ }
+/*
+ Register the incoming masterSecret and cipher, which could still be null,
+ depending on when we're called.
+*/
+ memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret,
+ SSL_HS_MASTER_SIZE);
+ sessionTable[i].cipher = ssl->cipher;
+ sessionTable[i].inUse = 1;
+ sslUnlockMutex(&sessionTableLock);
+/*
+ The sessionId is the current serverRandom value, with the first 4 bytes
+ replaced with the current cache index value for quick lookup later.
+ FUTURE SECURITY - Should generate more random bytes here for the session
+ id. We re-use the server random as the ID, which is OK, since it is
+ sent plaintext on the network, but an attacker listening to a resumed
+ connection will also be able to determine part of the original server
+ random used to generate the master key, even if he had not seen it
+ initially.
+*/
+ memcpy(sessionTable[i].id, ssl->sec.serverRandom,
+ min(SSL_HS_RANDOM_SIZE, SSL_MAX_SESSION_ID_SIZE));
+ ssl->sessionIdLen = SSL_MAX_SESSION_ID_SIZE;
+ sessionTable[i].id[0] = (unsigned char)(i & 0xFF);
+ sessionTable[i].id[1] = (unsigned char)((i & 0xFF00) >> 8);
+ sessionTable[i].id[2] = (unsigned char)((i & 0xFF0000) >> 16);
+ sessionTable[i].id[3] = (unsigned char)((i & 0xFF000000) >> 24);
+ memcpy(ssl->sessionId, sessionTable[i].id, SSL_MAX_SESSION_ID_SIZE);
+/*
+ startTime is used to check expiry of the entry
+ accessTime is used to for cache replacement logic
+ The versions are stored, because a cached session must be reused
+ with same SSL version.
+*/
+ sslInitMsecs(&sessionTable[i].startTime);
+ sessionTable[i].accessTime = sessionTable[i].startTime;
+ sessionTable[i].majVer = ssl->majVer;
+ sessionTable[i].minVer = ssl->minVer;
+ sessionTable[i].flag = 0;
+
+ return i;
+}
+
+/******************************************************************************/
+/*
+ Clear the inUse flag during re-handshakes so the entry may be found
+*/
+int32 matrixClearSession(ssl_t *ssl, int32 remove)
+{
+ char *id;
+ uint32 i;
+
+ if (ssl->sessionIdLen <= 0) {
+ return -1;
+ }
+ id = ssl->sessionId;
+
+ i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0];
+ if (i >= SSL_SESSION_TABLE_SIZE || i < 0) {
+ return -1;
+ }
+ sslLockMutex(&sessionTableLock);
+ sessionTable[i].inUse = 0;
+ sessionTable[i].flag = 0;
+/*
+ If this is a full removal, actually delete the entry rather than
+ just setting the inUse to 0. Also need to clear any RESUME flag
+ on the ssl connection so a new session will be correctly registered.
+*/
+ if (remove) {
+ memset(ssl->sessionId, 0x0, SSL_MAX_SESSION_ID_SIZE);
+ ssl->sessionIdLen = 0;
+ memset(&sessionTable[i], 0x0, sizeof(sslSessionEntry_t));
+ ssl->flags &= ~SSL_FLAGS_RESUMED;
+ }
+ sslUnlockMutex(&sessionTableLock);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Look up a session ID in the cache. If found, set the ssl masterSecret
+ and cipher to the pre-negotiated values
+*/
+int32 matrixResumeSession(ssl_t *ssl)
+{
+ char *id;
+ uint32 i;
+
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ return -1;
+ }
+ if (ssl->sessionIdLen <= 0) {
+ return -1;
+ }
+ id = ssl->sessionId;
+
+ i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0];
+
+ sslLockMutex(&sessionTableLock);
+ if (i >= SSL_SESSION_TABLE_SIZE || i < 0 ||
+ sessionTable[i].cipher == NULL) {
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+/*
+ Id looks valid. Update the access time for expiration check.
+ Expiration is done on daily basis (86400 seconds)
+*/
+ sslInitMsecs(&sessionTable[i].accessTime);
+ if (memcmp(sessionTable[i].id, id,
+ min(ssl->sessionIdLen, SSL_MAX_SESSION_ID_SIZE)) != 0 ||
+ sslDiffSecs(sessionTable[i].startTime,
+ sessionTable[i].accessTime) > 86400 ||
+ sessionTable[i].inUse ||
+ sessionTable[i].majVer != ssl->majVer ||
+ sessionTable[i].minVer != ssl->minVer) {
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+ memcpy(ssl->sec.masterSecret, sessionTable[i].masterSecret,
+ SSL_HS_MASTER_SIZE);
+ ssl->cipher = sessionTable[i].cipher;
+ sessionTable[i].inUse = 1;
+ sslUnlockMutex(&sessionTableLock);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Update session information in the cache.
+ This is called when we've determined the master secret and when we're
+ closing the connection to update various values in the cache.
+*/
+int32 matrixUpdateSession(ssl_t *ssl)
+{
+ char *id;
+ uint32 i;
+
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ return -1;
+ }
+ if ((id = ssl->sessionId) == NULL) {
+ return -1;
+ }
+ i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0];
+ if (i < 0 || i >= SSL_SESSION_TABLE_SIZE) {
+ return -1;
+ }
+/*
+ If there is an error on the session, invalidate for any future use
+*/
+ sslLockMutex(&sessionTableLock);
+ sessionTable[i].inUse = ssl->flags & SSL_FLAGS_CLOSED ? 0 : 1;
+ if (ssl->flags & SSL_FLAGS_ERROR) {
+ memset(sessionTable[i].masterSecret, 0x0, SSL_HS_MASTER_SIZE);
+ sessionTable[i].cipher = NULL;
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+ memcpy(sessionTable[i].masterSecret, ssl->sec.masterSecret,
+ SSL_HS_MASTER_SIZE);
+ sessionTable[i].cipher = ssl->cipher;
+ sslUnlockMutex(&sessionTableLock);
+ return 0;
+}
+
+int32 matrixSslSetResumptionFlag(ssl_t *ssl, char flag)
+{
+ char *id;
+ uint32 i;
+
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ return -1;
+ }
+ if ((id = ssl->sessionId) == NULL) {
+ return -1;
+ }
+ i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0];
+ if (i < 0 || i >= SSL_SESSION_TABLE_SIZE) {
+ return -1;
+ }
+ sslLockMutex(&sessionTableLock);
+ sessionTable[i].inUse = ssl->flags & SSL_FLAGS_CLOSED ? 0 : 1;
+ if (ssl->flags & SSL_FLAGS_ERROR) {
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+ sessionTable[i].flag = flag;
+ sslUnlockMutex(&sessionTableLock);
+ return 0;
+}
+
+int32 matrixSslGetResumptionFlag(ssl_t *ssl, char *flag)
+{
+ char *id;
+ uint32 i;
+
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ return -1;
+ }
+ if ((id = ssl->sessionId) == NULL) {
+ return -1;
+ }
+ i = (id[3] << 24) + (id[2] << 16) + (id[1] << 8) + id[0];
+ if (i < 0 || i >= SSL_SESSION_TABLE_SIZE) {
+ return -1;
+ }
+ sslLockMutex(&sessionTableLock);
+ sessionTable[i].inUse = ssl->flags & SSL_FLAGS_CLOSED ? 0 : 1;
+ if (ssl->flags & SSL_FLAGS_ERROR) {
+ sslUnlockMutex(&sessionTableLock);
+ return -1;
+ }
+ *flag = sessionTable[i].flag;
+ sslUnlockMutex(&sessionTableLock);
+ return 0;
+}
+#endif /* USE_SERVER_SIDE_SSL */
+
+#ifdef USE_CLIENT_SIDE_SSL
+/******************************************************************************/
+/*
+ Get session information from the ssl structure and populate the given
+ session structure. Session will contain a copy of the relevant session
+ information, suitable for creating a new, resumed session.
+*/
+int32 matrixSslGetSessionId(ssl_t *ssl, sslSessionId_t **session)
+{
+ sslSessionId_t *lsession;
+
+ if (ssl == NULL || ssl->flags & SSL_FLAGS_SERVER) {
+ return -1;
+ }
+
+ if (ssl->cipher != NULL && ssl->cipher->id != SSL_NULL_WITH_NULL_NULL &&
+ ssl->sessionIdLen == SSL_MAX_SESSION_ID_SIZE) {
+ *session = lsession = psMalloc(PEERSEC_BASE_POOL,
+ sizeof(sslSessionId_t));
+ if (lsession == NULL) {
+ return SSL_MEM_ERROR;
+ }
+ lsession->cipherId = ssl->cipher->id;
+ memcpy(lsession->id, ssl->sessionId, ssl->sessionIdLen);
+ memcpy(lsession->masterSecret, ssl->sec.masterSecret,
+ SSL_HS_MASTER_SIZE);
+ return 0;
+ }
+ return -1;
+}
+
+/******************************************************************************/
+/*
+ Must be called on session returned from matrixSslGetSessionId
+*/
+void matrixSslFreeSessionId(sslSessionId_t *sessionId)
+{
+ if (sessionId != NULL) {
+ psFree(sessionId);
+ }
+}
+#endif /* USE_CLIENT_SIDE_SSL */
+
+/******************************************************************************/
+/*
+ Rehandshake. Free any allocated sec members that will be repopulated
+*/
+void sslResetContext(ssl_t *ssl)
+{
+#ifdef USE_SERVER_SIDE_SSL
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+/*
+ Clear the inUse flag of the current session so it may be found again
+ if client attempts to reuse session id
+*/
+ matrixClearSession(ssl, 0);
+ }
+#endif /* USE_SERVER_SIDE_SSL */
+
+}
+
+/******************************************************************************/
+
+
+
diff --git a/contrib/libs/matrixssl/src/os/debug.c b/contrib/libs/matrixssl/src/os/debug.c
new file mode 100644
index 00000000000..3f0feb8f936
--- /dev/null
+++ b/contrib/libs/matrixssl/src/os/debug.c
@@ -0,0 +1,62 @@
+/*
+ * debug.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ */
+/*
+ * 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 "osLayer.h"
+
+/******************************************************************************/
+/*
+ Debugging APIs
+*/
+#ifdef MSSLDEBUG
+
+/* message should contain one %s, unless value is NULL */
+void matrixStrDebugMsg(char *message, char *value)
+{
+ if (value) {
+ printf(message, value);
+ } else {
+ printf(message);
+ }
+}
+
+/* message should contain one %d */
+void matrixIntDebugMsg(char *message, int32 value)
+{
+ printf(message, value);
+}
+
+/* message should contain one %p */
+void matrixPtrDebugMsg(char *message, void *value)
+{
+ printf(message, value);
+}
+
+#endif /* MSSLDEBUG */
+
+/******************************************************************************/
+
diff --git a/contrib/libs/matrixssl/src/os/osLayer.h b/contrib/libs/matrixssl/src/os/osLayer.h
new file mode 100644
index 00000000000..43d6e2a2253
--- /dev/null
+++ b/contrib/libs/matrixssl/src/os/osLayer.h
@@ -0,0 +1,110 @@
+/*
+ * osLayer.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Layered header for OS specific functions
+ * Contributors adding new OS support must implement all functions
+ * externed below.
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_OS_LAYER
+#define _h_OS_LAYER
+#define _h_EXPORT_SYMBOLS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <util/system/platform.h>
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+
+#include "../../matrixCommon.h"
+#include "psMalloc.h"
+
+/*
+ Functions defined at OS level
+*/
+extern int32 sslOpenOsdep(void);
+extern int32 sslCloseOsdep(void);
+extern int32 sslGetEntropy(unsigned char *bytes, int32 size);
+
+/*
+ Defines to make library multithreading safe
+*/
+typedef void * sslMutex_t;
+extern int32 sslCreateMutex(sslMutex_t *mutex);
+extern int32 sslLockMutex(sslMutex_t *mutex);
+extern int32 sslUnlockMutex(sslMutex_t *mutex);
+extern void sslDestroyMutex(sslMutex_t *mutex);
+
+
+typedef ui64 sslTime_t;
+extern int32 sslInitMsecs(sslTime_t *t);
+extern int32 sslCompareTime(sslTime_t a, sslTime_t b);
+extern int32 sslDiffSecs(sslTime_t then, sslTime_t now);
+extern long sslDiffMsecs(sslTime_t then, sslTime_t now);
+
+
+/******************************************************************************/
+/*
+ Debugging functionality.
+
+ If MSSLDEBUG is defined matrixStrDebugMsg and matrixIntDebugMsg messages are
+ output to stdout, sslAsserts go to stderror and call psBreak.
+
+ In non-MSSLDEBUG builds matrixStrDebugMsg and matrixIntDebugMsg are
+ compiled out. sslAsserts still go to stderr, but psBreak is not called.
+
+*/
+
+#ifdef MSSLDEBUG
+extern void psBreak(void);
+extern void matrixStrDebugMsg(char *message, char *arg);
+extern void matrixIntDebugMsg(char *message, int32 arg);
+extern void matrixPtrDebugMsg(char *message, void *arg);
+#define sslAssert(C) if (C) ; else \
+ {fprintf(stderr, "%s:%d sslAssert(%s)\n",__FILE__, __LINE__, #C); psBreak(); }
+#else
+#define matrixStrDebugMsg(x, y)
+#define matrixIntDebugMsg(x, y)
+#define matrixPtrDebugMsg(x, y)
+#define sslAssert(C) if (C) ; else \
+ {fprintf(stderr, "%s:%d sslAssert(%s)\n",__FILE__, __LINE__, #C); }
+#endif /* MSSLDEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_OS_LAYER */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/os/psMalloc.h b/contrib/libs/matrixssl/src/os/psMalloc.h
new file mode 100644
index 00000000000..d76f9a8982b
--- /dev/null
+++ b/contrib/libs/matrixssl/src/os/psMalloc.h
@@ -0,0 +1,60 @@
+/*
+ * psMalloc.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Header for psMalloc functions
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_PS_MALLOC
+#define _h_PS_MALLOC
+
+#define PEERSEC_BASE_POOL 0
+#define PEERSEC_NO_POOL (void *)0x00001
+
+/******************************************************************************/
+/*
+ Because a set of public APIs are exposed here there is a dependence on
+ the package. The config layer header must be parsed to determine what
+ defines are configured
+*/
+#include "../../matrixCommon.h"
+
+/*
+ Native memory routines
+*/
+#define MAX_MEMORY_USAGE 0
+#define psOpenMalloc(A) 0
+#define psCloseMalloc()
+#define psMalloc(A, B) malloc(B)
+#define psCalloc(A, B, C) calloc(B, C)
+#define psRealloc realloc
+#define psFree free
+#define psMemset memset
+#define psMemcpy memcpy
+typedef int32 psPool_t;
+
+#endif /* _h_PS_MALLOC */
diff --git a/contrib/libs/matrixssl/src/os/yandex/yandex.cpp b/contrib/libs/matrixssl/src/os/yandex/yandex.cpp
new file mode 100644
index 00000000000..6f9ed74205f
--- /dev/null
+++ b/contrib/libs/matrixssl/src/os/yandex/yandex.cpp
@@ -0,0 +1,68 @@
+#include <util/random/entropy.h>
+#include <util/system/datetime.h>
+#include <util/system/mutex.h>
+#include <util/stream/input.h>
+#include <util/generic/yexception.h>
+
+#include "../osLayer.h"
+
+int32 sslCreateMutex(sslMutex_t *mutex) {
+ *mutex = new TMutex();
+ return 0;
+}
+
+int32 sslLockMutex(sslMutex_t *mutex) {
+ Y_ASSERT(*mutex);
+ ((TMutex *)(*mutex))->Acquire();
+ return 0;
+}
+
+int32 sslUnlockMutex(sslMutex_t *mutex) {
+ Y_ASSERT(*mutex);
+ ((TMutex *)(*mutex))->Release();
+ return 0;
+}
+
+void sslDestroyMutex(sslMutex_t *mutex) {
+ delete (TMutex*)(*mutex);
+ *mutex = NULL;
+}
+
+int32 sslInitMsecs(sslTime_t *timePtr) {
+ *timePtr = millisec();
+ return (int32)(*timePtr);
+}
+
+long sslDiffMsecs(sslTime_t then, sslTime_t now) {
+ return (long)(now - then);
+}
+
+int32 sslDiffSecs(sslTime_t then, sslTime_t now) {
+ return (int32)((now - then) / 1000);
+}
+
+int32 sslCompareTime(sslTime_t a, sslTime_t b) {
+ return (a < b) ? 1 : 0;
+}
+
+int32 sslOpenOsdep(void) {
+ return 0;
+}
+
+int32 sslCloseOsdep(void) {
+ return 0;
+}
+
+int32 sslGetEntropy(unsigned char *bytes, int32 size) {
+ size_t read = EntropyPool().Load(bytes, size);
+ return (read ? read : -1);
+}
+
+#ifdef MSSLDEBUG
+void psBreak(void)
+{
+ abort();
+}
+#endif
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/pki/asn1.c b/contrib/libs/matrixssl/src/pki/asn1.c
new file mode 100644
index 00000000000..0261cc16644
--- /dev/null
+++ b/contrib/libs/matrixssl/src/pki/asn1.c
@@ -0,0 +1,454 @@
+/*
+ * asn1.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * DER/BER coding
+ */
+/*
+ * 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 "pkiInternal.h"
+
+/******************************************************************************/
+/*
+ On success, p will be updated to point to first character of value and
+ valLen will contain number of bytes in value
+ Return:
+ 0 Success
+ < 0 Error
+*/
+int32 asnParseLength(unsigned char **p, int32 size, int32 *valLen)
+{
+ unsigned char *c, *end;
+ int32 len, olen;
+
+ c = *p;
+ end = c + size;
+ if (end - c < 1) {
+ return -1;
+ }
+/*
+ If the length byte has high bit only set, it's an indefinite length
+ We don't support this!
+*/
+ if (*c == 0x80) {
+ *valLen = -1;
+ matrixStrDebugMsg("Unsupported: ASN indefinite length\n", NULL);
+ return -1;
+ }
+/*
+ If the high bit is set, the lower 7 bits represent the number of
+ bytes that follow and represent length
+ If the high bit is not set, the lower 7 represent the actual length
+*/
+ len = *c & 0x7F;
+ if (*(c++) & 0x80) {
+/*
+ Make sure there aren't more than 4 bytes of length specifier,
+ and that we have that many bytes left in the buffer
+*/
+ if (len > sizeof(int32) || len == 0x7f || (end - c) < len) {
+ return -1;
+ }
+ olen = 0;
+ while (len-- > 0) {
+ olen = (olen << 8) | *c;
+ c++;
+ }
+ if (olen < 0 || olen > INT_MAX) {
+ return -1;
+ }
+ len = olen;
+ }
+ *p = c;
+ *valLen = len;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Callback to extract a big int32 (stream of bytes) from the DER stream
+*/
+int32 getBig(psPool_t *pool, unsigned char **pp, int32 len, mp_int *big)
+{
+ unsigned char *p = *pp;
+ int32 vlen;
+
+ if (len < 1 || *(p++) != ASN_INTEGER ||
+ asnParseLength(&p, len - 1, &vlen) < 0 || (len -1) < vlen) {
+ matrixStrDebugMsg("ASN getBig failed\n", NULL);
+ return -1;
+ }
+ mp_init(pool, big);
+ if (mp_read_unsigned_bin(big, p, vlen) != 0) {
+ mp_clear(big);
+ matrixStrDebugMsg("ASN getBig failed\n", NULL);
+ return -1;
+ }
+ p += vlen;
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Although a certificate serial number is encoded as an integer type, that
+ doesn't prevent it from being abused as containing a variable length
+ binary value. Get it here.
+*/
+int32 getSerialNum(psPool_t *pool, unsigned char **pp, int32 len,
+ unsigned char **sn, int32 *snLen)
+{
+ unsigned char *p = *pp;
+ int32 vlen;
+
+ if ((*p != (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) &&
+ (*p != ASN_INTEGER)) {
+ matrixStrDebugMsg("ASN getSerialNumber failed\n", NULL);
+ return -1;
+ }
+ p++;
+
+ if (len < 1 || asnParseLength(&p, len - 1, &vlen) < 0 || (len - 1) < vlen) {
+ matrixStrDebugMsg("ASN getSerialNumber failed\n", NULL);
+ return -1;
+ }
+ *snLen = vlen;
+ *sn = psMalloc(pool, vlen);
+ if (*sn == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memcpy(*sn, p, vlen);
+ p += vlen;
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Callback to extract a sequence length from the DER stream
+ Verifies that 'len' bytes are >= 'seqlen'
+ Move pp to the first character in the sequence
+*/
+int32 getSequence(unsigned char **pp, int32 len, int32 *seqlen)
+{
+ unsigned char *p = *pp;
+
+ if (len < 1 || *(p++) != (ASN_SEQUENCE | ASN_CONSTRUCTED) ||
+ asnParseLength(&p, len - 1, seqlen) < 0 || len < *seqlen) {
+ return -1;
+ }
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Extract a set length from the DER stream
+*/
+int32 getSet(unsigned char **pp, int32 len, int32 *setlen)
+{
+ unsigned char *p = *pp;
+
+ if (len < 1 || *(p++) != (ASN_SET | ASN_CONSTRUCTED) ||
+ asnParseLength(&p, len - 1, setlen) < 0 || len < *setlen) {
+ return -1;
+ }
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Explicit value encoding has an additional tag layer
+*/
+int32 getExplicitVersion(unsigned char **pp, int32 len, int32 expVal, int32 *val)
+{
+ unsigned char *p = *pp;
+ int32 exLen;
+
+ if (len < 1) {
+ return -1;
+ }
+/*
+ This is an optional value, so don't error if not present. The default
+ value is version 1
+*/
+ if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | expVal)) {
+ *val = 0;
+ return 0;
+ }
+ p++;
+ if (asnParseLength(&p, len - 1, &exLen) < 0 || (len - 1) < exLen) {
+ return -1;
+ }
+ if (getInteger(&p, exLen, val) < 0) {
+ return -1;
+ }
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Implementation specific OID parser for suppported RSA algorithms
+*/
+int32 getAlgorithmIdentifier(unsigned char **pp, int32 len, int32 *oi,
+ int32 isPubKey)
+{
+ unsigned char *p = *pp, *end;
+ int32 arcLen, llen;
+
+ end = p + len;
+ if (len < 1 || getSequence(&p, len, &llen) < 0) {
+ return -1;
+ }
+ if (end - p < 1) {
+ return -1;
+ }
+ if (*(p++) != ASN_OID || asnParseLength(&p, (int32)(end - p), &arcLen) < 0 ||
+ llen < arcLen) {
+ return -1;
+ }
+/*
+ List of expected (currently supported) OIDs - RFC 3279
+ algorithm summed length hex
+ sha1 88 05 2b0e03021a
+ md2 646 08 2a864886f70d0202
+ md5 649 08 2a864886f70d0205
+
+ rsaEncryption 645 09 2a864886f70d010101
+ md2WithRSAEncryption: 646 09 2a864886f70d010102
+ md5WithRSAEncryption 648 09 2a864886f70d010104
+ sha-1WithRSAEncryption 649 09 2a864886f70d010105
+
+ Yes, the summing isn't ideal (as can be seen with the duplicate 649),
+ but the specific implementation makes this ok.
+*/
+ if (end - p < 2) {
+ return -1;
+ }
+ if (isPubKey && (*p != 0x2a) && (*(p + 1) != 0x86)) {
+/*
+ Expecting DSA here if not RSA, but OID doesn't always match
+*/
+ matrixStrDebugMsg("Unsupported algorithm identifier\n", NULL);
+ return -1;
+ }
+ *oi = 0;
+ while (arcLen-- > 0) {
+ *oi += (int32)*p++;
+ }
+/*
+ Each of these cases might have a trailing NULL parameter. Skip it
+*/
+ if (*p != ASN_NULL) {
+ *pp = p;
+ return 0;
+ }
+ if (end - p < 2) {
+ return -1;
+ }
+ *pp = p + 2;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Implementation specific date parser.
+ Does not actually verify the date
+*/
+int32 getValidity(psPool_t *pool, unsigned char **pp, int32 len,
+ char **notBefore, char **notAfter)
+{
+ unsigned char *p = *pp, *end;
+ int32 seqLen, timeLen;
+
+ end = p + len;
+ if (len < 1 || *(p++) != (ASN_SEQUENCE | ASN_CONSTRUCTED) ||
+ asnParseLength(&p, len - 1, &seqLen) < 0 || (end - p) < seqLen) {
+ return -1;
+ }
+/*
+ Have notBefore and notAfter times in UTCTime or GeneralizedTime formats
+*/
+ if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) {
+ return -1;
+ }
+ p++;
+/*
+ Allocate them as null terminated strings
+*/
+ if (asnParseLength(&p, seqLen, &timeLen) < 0 || (end - p) < timeLen) {
+ return -1;
+ }
+ *notBefore = psMalloc(pool, timeLen + 1);
+ if (*notBefore == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memcpy(*notBefore, p, timeLen);
+ (*notBefore)[timeLen] = '\0';
+ p = p + timeLen;
+ if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) {
+ return -1;
+ }
+ p++;
+ if (asnParseLength(&p, seqLen - timeLen, &timeLen) < 0 ||
+ (end - p) < timeLen) {
+ return -1;
+ }
+ *notAfter = psMalloc(pool, timeLen + 1);
+ if (*notAfter == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memcpy(*notAfter, p, timeLen);
+ (*notAfter)[timeLen] = '\0';
+ p = p + timeLen;
+
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Currently just returning the raw BIT STRING and size in bytes
+*/
+int32 getSignature(psPool_t *pool, unsigned char **pp, int32 len,
+ unsigned char **sig, int32 *sigLen)
+{
+ unsigned char *p = *pp, *end;
+ int32 ignore_bits, llen;
+
+ end = p + len;
+ if (len < 1 || (*(p++) != ASN_BIT_STRING) ||
+ asnParseLength(&p, len - 1, &llen) < 0 || (end - p) < llen) {
+ return -1;
+ }
+ ignore_bits = *p++;
+/*
+ We assume this is always 0.
+*/
+ sslAssert(ignore_bits == 0);
+/*
+ Length included the ignore_bits byte
+*/
+ *sigLen = llen - 1;
+ *sig = psMalloc(pool, *sigLen);
+ if (*sig == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memcpy(*sig, p, *sigLen);
+ *pp = p + *sigLen;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Could be optional. If the tag doesn't contain the value from the left
+ of the IMPLICIT keyword we don't have a match and we don't incr the pointer.
+*/
+int32 getImplicitBitString(psPool_t *pool, unsigned char **pp, int32 len,
+ int32 impVal, unsigned char **bitString, int32 *bitLen)
+{
+ unsigned char *p = *pp;
+ int32 ignore_bits;
+
+ if (len < 1) {
+ return -1;
+ }
+/*
+ We don't treat this case as an error, because of the optional nature.
+*/
+ if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | impVal)) {
+ return 0;
+ }
+
+ p++;
+ if (asnParseLength(&p, len, bitLen) < 0) {
+ return -1;
+ }
+ ignore_bits = *p++;
+ sslAssert(ignore_bits == 0);
+
+ *bitString = psMalloc(pool, *bitLen);
+ if (*bitString == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memcpy(*bitString, p, *bitLen);
+ *pp = p + *bitLen;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Get an integer
+*/
+int32 getInteger(unsigned char **pp, int32 len, int32 *val)
+{
+ unsigned char *p = *pp, *end;
+ uint32 ui;
+ int32 vlen;
+
+ end = p + len;
+ if (len < 1 || *(p++) != ASN_INTEGER ||
+ asnParseLength(&p, len - 1, &vlen) < 0) {
+ matrixStrDebugMsg("ASN getInteger failed\n", NULL);
+ return -1;
+ }
+/*
+ This check prevents us from having a big positive integer where the
+ high bit is set because it will be encoded as 5 bytes (with leading
+ blank byte). If that is required, a getUnsigned routine should be used
+*/
+ if (vlen > sizeof(int32) || end - p < vlen) {
+ matrixStrDebugMsg("ASN getInteger failed\n", NULL);
+ return -1;
+ }
+ ui = 0;
+/*
+ If high bit is set, it's a negative integer, so perform the two's compliment
+ Otherwise do a standard big endian read (most likely case for RSA)
+*/
+ if (*p & 0x80) {
+ while (vlen-- > 0) {
+ ui = (ui << 8) | (*p ^ 0xFF);
+ p++;
+ }
+ vlen = (int32)ui;
+ vlen++;
+ vlen = -vlen;
+ *val = vlen;
+ } else {
+ while (vlen-- > 0) {
+ ui = (ui << 8) | *p;
+ p++;
+ }
+ *val = (int32)ui;
+ }
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/pki/matrixPki.h b/contrib/libs/matrixssl/src/pki/matrixPki.h
new file mode 100644
index 00000000000..6d6beaa5e5d
--- /dev/null
+++ b/contrib/libs/matrixssl/src/pki/matrixPki.h
@@ -0,0 +1,137 @@
+/*
+ * matrixPki.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Public header file for MatrixPKI extension
+ * Implementations interacting with the PKI portion of the
+ * matrixssl library should only use the APIs and definitions
+ * used in this file.
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_MATRIXPKI
+#define _h_MATRIXPKI
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ Because the set of APIs exposed here is dependent on the package, the
+ crypto layer header must be parsed to determine what defines are configured
+ (USE_RSA, and USE_X509 specifically)
+*/
+#include "../../matrixCommon.h"
+#include "../crypto/matrixCrypto.h"
+
+#define REQ_FILE_TYPE 0
+#define KEY_FILE_TYPE 1
+#define CERT_FILE_TYPE 2
+
+#define MAX_CHAIN_LENGTH 128
+typedef uint32 sslChainLen_t[MAX_CHAIN_LENGTH];
+/******************************************************************************/
+/*
+ * PKI documented APIs
+ */
+MATRIXPUBLIC int32 matrixPkiOpen(void);
+MATRIXPUBLIC void matrixPkiClose(void);
+
+#ifdef USE_RSA
+/*
+ Private key reading and conversions
+*/
+#ifdef USE_FILE_SYSTEM
+MATRIXPUBLIC int32 matrixX509ReadPrivKey(psPool_t *pool, const char *fileName,
+ const char *password, unsigned char **out,
+ int32 *outLen);
+#endif /* USE_FILE_SYSTEM */
+MATRIXPUBLIC int32 matrixRsaParsePrivKey(psPool_t *pool, unsigned char *keyBuf,
+ int32 keyBufLen, sslRsaKey_t **key);
+MATRIXPUBLIC int32 matrixRsaParsePubKey(psPool_t *pool, unsigned char *keyBuf,
+ int32 keyBufLen, sslRsaKey_t **key);
+MATRIXPUBLIC void matrixRsaFreeKey(sslRsaKey_t *key);
+MATRIXPUBLIC int32 matrixRsaConvertToPublicKey(psPool_t *pool,
+ sslRsaKey_t *privKey, sslRsaKey_t **pubKey);
+
+/*
+ USE_X509 adds certificate support
+*/
+#ifdef USE_X509
+MATRIXPUBLIC int32 matrixX509ReadKeysMem(sslKeys_t **keys,
+ unsigned char *certBuf, int32 certLen,
+ unsigned char *privBuf, int32 privLen,
+ unsigned char *trustedCABuf, int32 trustedCALen);
+MATRIXPUBLIC void matrixRsaFreeKeys(sslKeys_t *keys);
+
+#ifdef USE_FILE_SYSTEM
+MATRIXPUBLIC int32 matrixX509ReadKeys(sslKeys_t **keys, const char *certFile,
+ const char *privFile, const char *privPass,
+ const char *trustedCAFile);
+MATRIXPUBLIC int32 matrixX509ReadKeysEx(psPool_t *pool, sslKeys_t **keys,
+ const char *certFile, const char *privFile,
+ const char *privPass, const char *trustedCAFiles);
+MATRIXPUBLIC int32 matrixX509ReadCert(psPool_t *pool, const char *fileName,
+ unsigned char **out, int32 *outLen,
+ sslChainLen_t *chain);
+MATRIXPUBLIC int32 matrixX509ReadPubKey(psPool_t *pool, const char *certFile,
+ sslRsaKey_t **key);
+#endif /* USE_FILE_SYSTEM */
+
+MATRIXPUBLIC int32 matrixRsaParseKeysMem(psPool_t *pool, sslKeys_t **keys,
+ unsigned char *certBuf, int32 certLen, unsigned char *privBuf,
+ int32 privLen, unsigned char *trustedCABuf, int32 trustedCALen);
+MATRIXPUBLIC int32 matrixX509ParseCert(psPool_t *pool, unsigned char *certBuf,
+ int32 certlen, sslCert_t **cert);
+MATRIXPUBLIC void matrixX509FreeCert(sslCert_t *cert);
+MATRIXPUBLIC int32 matrixX509ParsePubKey(psPool_t *pool, unsigned char *certBuf,
+ int32 certLen, sslRsaKey_t **key);
+MATRIXPUBLIC int32 matrixX509ValidateCert(psPool_t *pool,
+ sslCert_t *subjectCert, sslCert_t *issuerCert,
+ int32 *valid);
+MATRIXPUBLIC int32 matrixX509ValidateCertChain(psPool_t *pool,
+ sslCert_t *chain, sslCert_t **subjectCert,
+ int32 *valid);
+MATRIXPUBLIC int32 matrixX509UserValidator(psPool_t *pool,
+ sslCert_t *subjectCert,
+ int32 (*certValidator)(sslCertInfo_t *t, void *arg),
+ void *arg);
+#endif /* USE_X509 */
+
+
+
+#endif /* USE_RSA */
+
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MATRIXPKI */
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/pki/pkiInternal.h b/contrib/libs/matrixssl/src/pki/pkiInternal.h
new file mode 100644
index 00000000000..729d06184be
--- /dev/null
+++ b/contrib/libs/matrixssl/src/pki/pkiInternal.h
@@ -0,0 +1,239 @@
+/*
+ * pkiInternal.h
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Public header file for MatrixSSL PKI extension
+ * Implementations interacting with the PKI portion of the
+ * matrixssl library should only use the APIs and definitions
+ * used in this file.
+ */
+/*
+ * 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
+ */
+/******************************************************************************/
+
+#ifndef _h_PSPKI_INTERNAL
+#define _h_PSPKI_INTERNAL
+#define _h_EXPORT_SYMBOLS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ Require OS for PeerSec malloc and crypto to determine what we include here
+*/
+#include "../../matrixCommon.h"
+#include "../os/osLayer.h"
+#include "../crypto/cryptoLayer.h"
+
+/******************************************************************************/
+/*
+ ASN defines
+
+ 8 bit bit masks for ASN.1 tag field
+*/
+#define ASN_PRIMITIVE 0x0
+#define ASN_CONSTRUCTED 0x20
+
+#define ASN_UNIVERSAL 0x0
+#define ASN_APPLICATION 0x40
+#define ASN_CONTEXT_SPECIFIC 0x80
+#define ASN_PRIVATE 0xC0
+
+/*
+ ASN.1 primitive data types
+*/
+enum {
+ ASN_BOOLEAN = 1,
+ ASN_INTEGER,
+ ASN_BIT_STRING,
+ ASN_OCTET_STRING,
+ ASN_NULL,
+ ASN_OID,
+ ASN_UTF8STRING = 12,
+ ASN_SEQUENCE = 16,
+ ASN_SET,
+ ASN_PRINTABLESTRING = 19,
+ ASN_T61STRING,
+ ASN_IA5STRING = 22,
+ ASN_UTCTIME,
+ ASN_GENERALIZEDTIME,
+ ASN_GENERAL_STRING = 27,
+ ASN_BMPSTRING = 30
+};
+
+
+extern int32 getBig(psPool_t *pool, unsigned char **pp, int32 len, mp_int *big);
+extern int32 getSerialNum(psPool_t *pool, unsigned char **pp, int32 len,
+ unsigned char **sn, int32 *snLen);
+extern int32 getInteger(unsigned char **pp, int32 len, int32 *val);
+extern int32 getSequence(unsigned char **pp, int32 len, int32 *outLen);
+extern int32 getSet(unsigned char **pp, int32 len, int32 *outLen);
+extern int32 getExplicitVersion(unsigned char **pp, int32 len, int32 expVal,
+ int32 *outLen);
+extern int32 getAlgorithmIdentifier(unsigned char **pp, int32 len, int32 *oi,
+ int32 isPubKey);
+extern int32 getValidity(psPool_t *pool, unsigned char **pp, int32 len,
+ char **notBefore, char **notAfter);
+extern int32 getSignature(psPool_t *pool, unsigned char **pp, int32 len,
+ unsigned char **sig, int32 *sigLen);
+extern int32 getImplicitBitString(psPool_t *pool, unsigned char **pp, int32 len,
+ int32 impVal, unsigned char **bitString, int32 *bitLen);
+
+/*
+ Define to enable more extension parsing
+*/
+#define USE_FULL_CERT_PARSE
+
+/******************************************************************************/
+/*
+ The USE_RSA define is primarily for future compat when more key exchange
+ protocols are added. Crypto should always define this for now.
+*/
+#define OID_RSA_MD2 646
+#define OID_RSA_MD5 648
+#define OID_RSA_SHA1 649
+
+/*
+ DN attributes are used outside the X509 area for cert requests,
+ which have been included in the RSA portions of the code
+*/
+typedef struct {
+ char *country;
+ char *state;
+ char *locality;
+ char *organization;
+ char *orgUnit;
+ char *commonName;
+ char hash[SSL_SHA1_HASH_SIZE];
+} DNattributes_t;
+
+
+#ifdef USE_X509
+
+typedef struct {
+ int32 ca;
+ int32 pathLenConstraint;
+} extBasicConstraints_t;
+
+typedef struct {
+ int32 len;
+ unsigned char *id;
+} extSubjectKeyId_t;
+
+typedef struct {
+ int32 keyLen;
+ unsigned char *keyId;
+ DNattributes_t attribs;
+ int32 serialNumLen;
+ unsigned char *serialNum;
+} extAuthKeyId_t;
+/*
+ FUTURE: add support for the other extensions
+*/
+typedef struct {
+ extBasicConstraints_t bc;
+ sslSubjectAltName_t *san;
+#ifdef USE_FULL_CERT_PARSE
+ extSubjectKeyId_t sk;
+ extAuthKeyId_t ak;
+ unsigned char *keyUsage;
+ int32 keyUsageLen;
+#endif /* USE_FULL_CERT_PARSE */
+} v3extensions_t;
+
+typedef struct sslCert {
+ int32 version;
+ int32 valid;
+ unsigned char *serialNumber;
+ int32 serialNumberLen;
+ DNattributes_t issuer;
+ DNattributes_t subject;
+ char *notBefore;
+ char *notAfter;
+ sslRsaKey_t publicKey;
+ int32 certAlgorithm;
+ int32 sigAlgorithm;
+ int32 pubKeyAlgorithm;
+ unsigned char *signature;
+ int32 signatureLen;
+ unsigned char sigHash[SSL_SHA1_HASH_SIZE];
+ unsigned char *uniqueUserId;
+ int32 uniqueUserIdLen;
+ unsigned char *uniqueSubjectId;
+ int32 uniqueSubjectIdLen;
+ v3extensions_t extensions;
+ struct sslCert *next;
+} sslCert_t;
+
+typedef struct sslLocalCert {
+ sslRsaKey_t *privKey;
+ unsigned char *certBin;
+ uint32 certLen;
+ struct sslLocalCert *next;
+} sslLocalCert_t;
+
+typedef struct {
+ sslLocalCert_t cert;
+#ifdef USE_CLIENT_SIDE_SSL
+ sslCert_t *caCerts;
+#endif /* USE_CLIENT_SIDE_SSL */
+} sslKeys_t;
+
+#endif /* USE_X509 */
+
+
+
+/*
+ Helpers for inter-pki communications
+*/
+extern int32 asnParseLength(unsigned char **p, int32 size, int32 *valLen);
+extern int32 psAsnConfirmSignature(unsigned char *sigHash,
+ unsigned char *sigOut, int32 sigLen);
+extern int32 getDNAttributes(psPool_t *pool, unsigned char **pp, int32 len,
+ DNattributes_t *attribs);
+extern int32 getPubKey(psPool_t *pool, unsigned char **pp, int32 len,
+ sslRsaKey_t *pubKey);
+extern void psFreeDNStruct(DNattributes_t *dn);
+
+#ifdef USE_FILE_SYSTEM
+extern int32 readCertChain(psPool_t *pool, const char *certFiles,
+ sslLocalCert_t *lkeys);
+extern int32 psGetFileBin(psPool_t *pool, const char *fileName,
+ unsigned char **bin, int32 *binLen);
+extern int32 base64encodeAndWrite(psPool_t *pool, const char *fileName,
+ unsigned char *bin, int32 binLen, int32 fileType,
+ char *hexCipherIV, int32 hexCipherIVLen);
+#endif /* USE_FILE_SYSTEM */
+
+/*
+ Finally, include the public header
+*/
+#include "matrixPki.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_PSPKI_INTERNAL */
diff --git a/contrib/libs/matrixssl/src/pki/rsaPki.c b/contrib/libs/matrixssl/src/pki/rsaPki.c
new file mode 100644
index 00000000000..9b83029ffd8
--- /dev/null
+++ b/contrib/libs/matrixssl/src/pki/rsaPki.c
@@ -0,0 +1,681 @@
+/*
+ * rsaPki.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * RSA key and cert reading
+ */
+/*
+ * 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 "pkiInternal.h"
+
+#ifdef USE_FILE_SYSTEM
+ #include <sys/stat.h>
+ #include <signal.h>
+#endif /* USE_FILE_SYSTEM */
+/*
+ For our purposes USE_RSA is used to indicate RSA private key handling.
+ USE_X509 indicates certificate handling and those blocks should be
+ wrapped inside USE_RSA because that is the only key type currently supported
+*/
+#ifdef USE_RSA
+
+#define ATTRIB_COUNTRY_NAME 6
+#define ATTRIB_LOCALITY 7
+#define ATTRIB_ORGANIZATION 10
+#define ATTRIB_ORG_UNIT 11
+#define ATTRIB_DN_QUALIFIER 46
+#define ATTRIB_STATE_PROVINCE 8
+#define ATTRIB_COMMON_NAME 3
+
+
+#ifdef USE_3DES
+static const char encryptHeader[] = "DEK-Info: DES-EDE3-CBC,";
+static int32 hexToBinary(unsigned char *hex, unsigned char *bin, int32 binlen);
+#endif
+
+static int32 psAsnParsePrivateKey(psPool_t *pool, unsigned char **pp,
+ int32 size, sslRsaKey_t *key);
+#endif /* USE_RSA */
+
+
+/******************************************************************************/
+/*
+ Open and close the PKI module. These routines are called once in the
+ lifetime of the application and initialize and clean up the library
+ respectively.
+*/
+int32 matrixPkiOpen(void)
+{
+ if (sslOpenOsdep() < 0) {
+ matrixStrDebugMsg("Osdep open failure\n", NULL);
+ return -1;
+ }
+ return 0;
+}
+
+void matrixPkiClose(void)
+{
+ sslCloseOsdep();
+}
+#ifdef USE_FILE_SYSTEM
+/******************************************************************************/
+/*
+ Return the file contents given a file name in a single allocated buffer.
+ Not a good routine to use generally with the fixed mem stuff. Not
+ actually doing a 'binary' file read. Only using the 'r' attribute since
+ all the cert and key files are text.
+*/
+int32 psGetFileBin(psPool_t *pool, const char *fileName, unsigned char **bin,
+ int32 *binLen)
+{
+ FILE *fp;
+ struct stat fstat;
+ size_t tmp = 0;
+
+ *binLen = 0;
+ *bin = NULL;
+
+ if (fileName == NULL) {
+ return -1;
+ }
+ if ((stat(fileName, &fstat) != 0) || (fp = fopen(fileName, "r")) == NULL) {
+ return -7; /* FILE_NOT_FOUND */
+ }
+
+ *bin = psMalloc(pool, fstat.st_size + 1);
+ if (*bin == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(*bin, 0x0, fstat.st_size + 1);
+ while (((tmp = fread(*bin + *binLen, sizeof(char), 512, fp)) > 0) &&
+ (*binLen < fstat.st_size)) {
+ *binLen += (int32)tmp;
+ }
+ fclose(fp);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Public API to return an ASN.1 encoded key stream from a PEM private
+ * key file
+ *
+ * If password is provided, we only deal with 3des cbc encryption
+ * Function allocates key on success. User must free.
+ */
+int32 matrixX509ReadPrivKey(psPool_t *pool, const char *fileName,
+ const char *password, unsigned char **keyMem, int32 *keyMemLen)
+{
+ unsigned char *keyBuf, *DERout;
+ char *start, *end, *endTmp;
+ int32 keyBufLen, rc, DERlen, PEMlen = 0;
+#ifdef USE_3DES
+ sslCipherContext_t ctx;
+ unsigned char passKey[SSL_DES3_KEY_LEN];
+ unsigned char cipherIV[SSL_DES3_IV_LEN];
+ int32 tmp, encrypted = 0;
+#endif /* USE_3DES */
+
+ if (fileName == NULL) {
+ return 0;
+ }
+ *keyMem = NULL;
+ if ((rc = psGetFileBin(pool, fileName, &keyBuf, &keyBufLen)) < 0) {
+ return rc;
+ }
+ start = end = NULL;
+
+/*
+ * Check header and encryption parameters.
+ */
+ if (((start = strstr((char*)keyBuf, "-----BEGIN")) != NULL) &&
+ ((start = strstr((char*)keyBuf, "PRIVATE KEY-----")) != NULL) &&
+ ((end = strstr(start, "-----END")) != NULL) &&
+ ((endTmp = strstr(end, "PRIVATE KEY-----")) != NULL)) {
+ start += strlen("PRIVATE KEY-----");
+ while (*start == '\r' || *start == '\n') {
+ start++;
+ }
+ PEMlen = (int32)(end - start);
+ } else {
+ matrixStrDebugMsg("Error parsing private key buffer\n", NULL);
+ psFree(keyBuf);
+ return -1;
+ }
+
+ if (strstr((char*)keyBuf, "Proc-Type:") &&
+ strstr((char*)keyBuf, "4,ENCRYPTED")) {
+#ifdef USE_3DES
+ encrypted++;
+ if (password == NULL) {
+ matrixStrDebugMsg("No password given for encrypted private key\n",
+ NULL);
+ psFree(keyBuf);
+ return -1;
+ }
+ if ((start = strstr((char*)keyBuf, encryptHeader)) == NULL) {
+ matrixStrDebugMsg("Unrecognized private key file encoding\n",
+ NULL);
+ psFree(keyBuf);
+ return -1;
+ }
+ start += strlen(encryptHeader);
+ /* SECURITY - we assume here that header points to at least 16 bytes of data */
+ tmp = hexToBinary((unsigned char*)start, cipherIV, SSL_DES3_IV_LEN);
+ if (tmp < 0) {
+ matrixStrDebugMsg("Invalid private key file salt\n", NULL);
+ psFree(keyBuf);
+ return -1;
+ }
+ start += tmp;
+ generate3DESKey((unsigned char*)password, (int32)strlen(password),
+ cipherIV, (unsigned char*)passKey);
+ PEMlen = (int32)(end - start);
+#else /* !USE_3DES */
+/*
+ * The private key is encrypted, but 3DES support has been turned off
+ */
+ matrixStrDebugMsg("3DES has been disabled for private key decrypt\n", NULL);
+ psFree(keyBuf);
+ return -1;
+#endif /* USE_3DES */
+ }
+
+/*
+ Take the raw input and do a base64 decode
+ */
+ DERout = psMalloc(pool, PEMlen);
+ if (DERout == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ DERlen = PEMlen;
+ if (ps_base64_decode((unsigned char*)start, PEMlen, DERout,
+ (uint32*)&DERlen) != 0) {
+ psFree(DERout);
+ psFree(keyBuf);
+ matrixStrDebugMsg("Unable to base64 decode private key\n", NULL);
+ return -1;
+ }
+ psFree(keyBuf);
+#ifdef USE_3DES
+/*
+ * Decode
+ */
+ if (encrypted == 1 && password) {
+ matrix3desInit(&ctx, cipherIV, passKey, SSL_DES3_KEY_LEN);
+ matrix3desDecrypt(&ctx, DERout, DERout, DERlen);
+ }
+#endif /* USE_3DES */
+/*
+ Don't parse this here. Return the ASN.1 encoded buf to be
+ consistent with the other mem APIs. Use the ParsePrivKey
+ function if you want the structure format
+*/
+ *keyMem = DERout;
+ *keyMemLen = DERlen;
+ return rc;
+}
+
+#ifdef USE_3DES
+/******************************************************************************/
+/*
+ Convert an ASCII hex representation to a binary buffer.
+ Decode enough data out of 'hex' buffer to produce 'binlen' bytes in 'bin'
+ Two digits of ASCII hex map to the high and low nybbles (in that order),
+ so this function assumes that 'hex' points to 2x 'binlen' bytes of data.
+ Return the number of bytes processed from hex (2x binlen) or < 0 on error.
+*/
+static int32 hexToBinary(unsigned char *hex, unsigned char *bin, int32 binlen)
+{
+ unsigned char *end, c, highOrder;
+
+ highOrder = 1;
+ for (end = hex + binlen * 2; hex < end; hex++) {
+ c = *hex;
+ if ('0' <= c && c <='9') {
+ c -= '0';
+ } else if ('a' <= c && c <='f') {
+ c -= ('a' - 10);
+ } else if ('A' <= c && c <='F') {
+ c -= ('A' - 10);
+ } else {
+ return -1;
+ }
+ if (highOrder++ & 0x1) {
+ *bin = c << 4;
+ } else {
+ *bin |= c;
+ bin++;
+ }
+ }
+ return binlen * 2;
+}
+#endif /* USE_3DES */
+#endif /* USE_FILE_SYSTEM */
+
+/******************************************************************************/
+/*
+ * In memory version of matrixRsaReadPrivKey. The keyBuf is the raw
+ * ASN.1 encoded buffer.
+ */
+int32 matrixRsaParsePrivKey(psPool_t *pool, unsigned char *keyBuf,
+ int32 keyBufLen, sslRsaKey_t **key)
+{
+ unsigned char *asnp;
+
+/*
+ Now have the DER stream to extract from in asnp
+ */
+ *key = psMalloc(pool, sizeof(sslRsaKey_t));
+ if (*key == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(*key, 0x0, sizeof(sslRsaKey_t));
+
+ asnp = keyBuf;
+ if (psAsnParsePrivateKey(pool, &asnp, keyBufLen, *key) < 0) {
+ matrixRsaFreeKey(*key);
+ *key = NULL;
+ matrixStrDebugMsg("Unable to ASN parse private key.\n", NULL);
+ return -1;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Binary to struct helper for RSA public keys.
+*/
+int32 matrixRsaParsePubKey(psPool_t *pool, unsigned char *keyBuf,
+ int32 keyBufLen, sslRsaKey_t **key)
+{
+ unsigned char *p, *end;
+ int32 len;
+
+ p = keyBuf;
+ end = p + keyBufLen;
+/*
+ Supporting both the PKCS#1 RSAPublicKey format and the
+ X.509 SubjectPublicKeyInfo format. If encoding doesn't start with
+ the SEQUENCE identifier for the SubjectPublicKeyInfo format, jump down
+ to the RSAPublicKey subset parser and try that
+*/
+ if (getSequence(&p, (int32)(end - p), &len) == 0) {
+ if (getAlgorithmIdentifier(&p, (int32)(end - p), &len, 1) < 0) {
+ return -1;
+ }
+ }
+/*
+ Now have the DER stream to extract from in asnp
+ */
+ *key = psMalloc(pool, sizeof(sslRsaKey_t));
+ if (*key == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(*key, 0x0, sizeof(sslRsaKey_t));
+ if (getPubKey(pool, &p, (int32)(end - p), *key) < 0) {
+ matrixRsaFreeKey(*key);
+ *key = NULL;
+ matrixStrDebugMsg("Unable to ASN parse public key\n", NULL);
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Free an RSA key. mp_clear will zero the memory of each element and free it.
+ */
+void matrixRsaFreeKey(sslRsaKey_t *key)
+{
+ mp_clear(&(key->N));
+ mp_clear(&(key->e));
+ mp_clear(&(key->d));
+ mp_clear(&(key->p));
+ mp_clear(&(key->q));
+ mp_clear(&(key->dP));
+ mp_clear(&(key->dQ));
+ mp_clear(&(key->qP));
+ psFree(key);
+}
+
+/******************************************************************************/
+/*
+ Parse a a private key structure in DER formatted ASN.1
+ Per ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
+ RSAPrivateKey ::= SEQUENCE {
+ version Version,
+ modulus INTEGER, -- n
+ publicExponent INTEGER, -- e
+ privateExponent INTEGER, -- d
+ prime1 INTEGER, -- p
+ prime2 INTEGER, -- q
+ exponent1 INTEGER, -- d mod (p-1)
+ exponent2 INTEGER, -- d mod (q-1)
+ coefficient INTEGER, -- (inverse of q) mod p
+ otherPrimeInfos OtherPrimeInfos OPTIONAL
+ }
+ Version ::= INTEGER { two-prime(0), multi(1) }
+ (CONSTRAINED BY {-- version must be multi if otherPrimeInfos present --})
+
+ Which should look something like this in hex (pipe character
+ is used as a delimiter):
+ ftp://ftp.rsa.com/pub/pkcs/ascii/layman.asc
+ 30 Tag in binary: 00|1|10000 -> UNIVERSAL | CONSTRUCTED | SEQUENCE (16)
+ 82 Length in binary: 1 | 0000010 -> LONG LENGTH | LENGTH BYTES (2)
+ 04 A4 Length Bytes (1188)
+ 02 Tag in binary: 00|0|00010 -> UNIVERSAL | PRIMITIVE | INTEGER (2)
+ 01 Length in binary: 0|0000001 -> SHORT LENGTH | LENGTH (1)
+ 00 INTEGER value (0) - RSAPrivateKey.version
+ 02 Tag in binary: 00|0|00010 -> UNIVERSAL | PRIMITIVE | INTEGER (2)
+ 82 Length in binary: 1 | 0000010 -> LONG LENGTH | LENGTH BYTES (2)
+ 01 01 Length Bytes (257)
+ [] 257 Bytes of data - RSAPrivateKey.modulus (2048 bit key)
+ 02 Tag in binary: 00|0|00010 -> UNIVERSAL | PRIMITIVE | INTEGER (2)
+ 03 Length in binary: 0|0000011 -> SHORT LENGTH | LENGTH (3)
+ 01 00 01 INTEGER value (65537) - RSAPrivateKey.publicExponent
+ ...
+
+ OtherPrimeInfos is not supported in this routine, and an error will be
+ returned if they are present
+*/
+
+static int32 psAsnParsePrivateKey(psPool_t *pool, unsigned char **pp,
+ int32 size, sslRsaKey_t *key)
+{
+ unsigned char *p, *end, *seq;
+ int32 version, seqlen;
+
+ key->optimized = 0;
+ p = *pp;
+ end = p + size;
+
+ if (getSequence(&p, size, &seqlen) < 0) {
+ matrixStrDebugMsg("ASN sequence parse error\n", NULL);
+ return -1;
+ }
+ seq = p;
+ if (getInteger(&p, (int32)(end - p), &version) < 0 || version != 0 ||
+ getBig(pool, &p, (int32)(end - p), &(key->N)) < 0 ||
+ mp_shrink(&key->N) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->e)) < 0 ||
+ mp_shrink(&key->e) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->d)) < 0 ||
+ mp_shrink(&key->d) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->p)) < 0 ||
+ mp_shrink(&key->p) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->q)) < 0 ||
+ mp_shrink(&key->q) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->dP)) < 0 ||
+ mp_shrink(&key->dP) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->dQ)) < 0 ||
+ mp_shrink(&key->dQ) != MP_OKAY ||
+ getBig(pool, &p, (int32)(end - p), &(key->qP)) < 0 ||
+ mp_shrink(&key->qP) != MP_OKAY ||
+ (int32)(p - seq) != seqlen) {
+ matrixStrDebugMsg("ASN key extract parse error\n", NULL);
+ return -1;
+ }
+/*
+ If we made it here, the key is ready for optimized decryption
+*/
+ key->optimized = 1;
+
+ *pp = p;
+/*
+ Set the key length of the key
+*/
+ key->size = mp_unsigned_bin_size(&key->N);
+ return 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) {
+ unsigned char *setend;
+ if (getSet(&p, (int32)(dnEnd - p), &setlen) < 0) {
+ return -1;
+ }
+ setend = p + setlen;
+
+ do {
+ 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++;
+
+ if (asnParseLength(&p, (int32)(dnEnd - p), &llen) < 0 ||
+ 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';
+/*
+ Catch any hidden \0 chars in these members to address the
+ issue of www.goodguy.com\0badguy.com
+*/
+ if (stringType != ASN_BMPSTRING && strlen(stringOut) != llen) {
+ psFree(stringOut);
+ return -1;
+ }
+
+ 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);
+ }
+ } while (p < setend);
+ }
+ matrixSha1Final(&hash, (unsigned char*)attribs->hash);
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Get the BIT STRING key and plug into RSA structure. Not included in
+ asn1.c because it deals directly with the sslRsaKey_t struct.
+*/
+int32 getPubKey(psPool_t *pool, unsigned char **pp, int32 len,
+ sslRsaKey_t *pubKey)
+{
+ unsigned char *p = *pp;
+ int32 pubKeyLen, ignore_bits, seqLen;
+
+ if (len < 1 || (*(p++) != ASN_BIT_STRING) ||
+ asnParseLength(&p, len - 1, &pubKeyLen) < 0 ||
+ (len - 1) < pubKeyLen) {
+ return -1;
+ }
+
+ ignore_bits = *p++;
+/*
+ We assume this is always zero
+*/
+ sslAssert(ignore_bits == 0);
+
+ if (getSequence(&p, pubKeyLen, &seqLen) < 0 ||
+ getBig(pool, &p, seqLen, &pubKey->N) < 0 ||
+ getBig(pool, &p, seqLen, &pubKey->e) < 0) {
+ return -1;
+ }
+ pubKey->size = mp_unsigned_bin_size(&pubKey->N);
+
+ *pp = p;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Free helper
+*/
+void psFreeDNStruct(DNattributes_t *dn)
+{
+ if (dn->country) psFree(dn->country);
+ if (dn->state) psFree(dn->state);
+ if (dn->locality) psFree(dn->locality);
+ if (dn->organization) psFree(dn->organization);
+ if (dn->orgUnit) psFree(dn->orgUnit);
+ if (dn->commonName) psFree(dn->commonName);
+}
+
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/pki/x509.c b/contrib/libs/matrixssl/src/pki/x509.c
new file mode 100644
index 00000000000..3ef307e076e
--- /dev/null
+++ b/contrib/libs/matrixssl/src/pki/x509.c
@@ -0,0 +1,1696 @@
+/*
+ * x509.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * DER/BER coding
+ */
+/*
+ * 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 "pkiInternal.h"
+
+/*
+ X509 is wrapped in USE_RSA until more key types are added
+*/
+#ifdef USE_RSA
+#ifdef USE_X509
+
+#define IMPLICIT_ISSUER_ID 1
+#define IMPLICIT_SUBJECT_ID 2
+#define EXPLICIT_EXTENSION 3
+
+#define RSA_SIG 1
+#define DSA_SIG 2
+
+#define OID_SHA1 88
+#define OID_MD2 646
+#define OID_MD5 649
+
+/*
+ Certificate extension hash mappings
+*/
+#define EXT_BASIC_CONSTRAINTS 1
+#define EXT_KEY_USAGE 2
+#define EXT_SUBJ_KEY_ID 3
+#define EXT_AUTH_KEY_ID 4
+#define EXT_ALT_SUBJECT_NAME 5
+
+static const struct {
+ unsigned char hash[16];
+ int32 id;
+} extTable[] = {
+ { { 0xa5, 0xc4, 0x5e, 0x9a, 0xa3, 0xbb, 0x71, 0x2f, 0x07,
+ 0xf7, 0x4c, 0xd0, 0xcd, 0x95, 0x65, 0xda }, EXT_BASIC_CONSTRAINTS },
+ { { 0xf5, 0xab, 0x88, 0x49, 0xc4, 0xfd, 0xa2, 0x64, 0x6d,
+ 0x06, 0xa2, 0x3e, 0x83, 0x9b, 0xef, 0xbb }, EXT_KEY_USAGE },
+ { { 0x91, 0x54, 0x28, 0xcc, 0x81, 0x59, 0x8c, 0x71, 0x8c,
+ 0x53, 0xa8, 0x4d, 0xeb, 0xd3, 0xc2, 0x18 }, EXT_SUBJ_KEY_ID },
+ { { 0x48, 0x2d, 0xff, 0x49, 0xf7, 0xab, 0x93, 0xe8, 0x1f,
+ 0x57, 0xb5, 0xaf, 0x7f, 0xaa, 0x31, 0xbb }, EXT_AUTH_KEY_ID },
+ { { 0x5c, 0x70, 0xcb, 0xf5, 0xa4, 0x07, 0x5a, 0xcc, 0xd1,
+ 0x55, 0xd2, 0x44, 0xdd, 0x62, 0x2c, 0x0c }, EXT_ALT_SUBJECT_NAME },
+ { { 0 }, -1 } /* Must be last for proper termination */
+};
+
+
+static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp,
+ int32 len, int32 expVal,
+ v3extensions_t *extensions);
+static int32 matrixX509ValidateCertInternal(psPool_t *pool,
+ sslCert_t *subjectCert, sslCert_t *issuerCert, int32 chain);
+#ifdef USE_FILE_SYSTEM
+static int32 parseList(psPool_t *pool, const char *list, const char *sep,
+ char **item);
+#endif /* USE_FILE_SYSTEM */
+
+/******************************************************************************/
+/*
+ Read in the certificate and private keys from the given files
+ If privPass is non-NULL, it will be used to decode an encrypted private
+ key file.
+
+ The certificate is stored internally as a pointer to DER encoded X.509
+ The private key is stored in a crypto provider specific structure
+*/
+#ifdef USE_FILE_SYSTEM
+int32 matrixX509ReadKeys(sslKeys_t **keys, const char *certFile,
+ const char *privFile, const char *privPass,
+ const char *trustedCAFiles)
+{
+ return matrixX509ReadKeysEx(PEERSEC_BASE_POOL, keys, certFile, privFile,
+ privPass, trustedCAFiles);
+}
+#else /* USE_FILE_SYSTEM */
+int32 matrixX509ReadKeys(sslKeys_t **keys, char *certFile, char *privFile,
+ char *privPass, char *trustedCAFile)
+{
+ matrixStrDebugMsg("Error: Calling matrixX509ReadKeys against a library " \
+ "built without USE_FILE_SYSTEM defined\n", NULL);
+ return -1;
+}
+#endif /* USE_FILE_SYSTEM */
+
+/******************************************************************************/
+/*
+ In memory version of matrixX509ReadKeys. The buffers are the ASN.1 raw
+ stream (ie. not base64 PEM encoded)
+
+ API CHANGE: 1.7 changed this protoype and buffer formats (ASN.1 now) but
+ this function was never properly documented. Users who may have found
+ this function on their own and are using it will need to convert to this
+ new version.
+*/
+int32 matrixX509ReadKeysMem(sslKeys_t **keys, unsigned char *certBuf,
+ int32 certLen, unsigned char *privBuf, int32 privLen,
+ unsigned char *trustedCABuf, int32 trustedCALen)
+{
+ return matrixRsaParseKeysMem(PEERSEC_BASE_POOL, keys, certBuf, certLen,
+ privBuf, privLen, trustedCABuf, trustedCALen);
+}
+
+/******************************************************************************/
+/*
+ Free private key and cert and zero memory allocated by matrixSslReadKeys.
+*/
+void matrixRsaFreeKeys(sslKeys_t *keys)
+{
+ sslLocalCert_t *current, *next;
+ int32 i = 0;
+
+ if (keys) {
+ current = &keys->cert;
+ while (current) {
+ if (current->certBin) {
+ memset(current->certBin, 0x0, current->certLen);
+ psFree(current->certBin);
+ }
+ if (current->privKey) {
+ matrixRsaFreeKey(current->privKey);
+ }
+ next = current->next;
+ if (i++ > 0) {
+ psFree(current);
+ }
+ current = next;
+ }
+#ifdef USE_CLIENT_SIDE_SSL
+ if (keys->caCerts) {
+ matrixX509FreeCert(keys->caCerts);
+ }
+#endif /* USE_CLIENT_SIDE_SSL */
+ psFree(keys);
+ }
+}
+
+#ifdef USE_FILE_SYSTEM
+/******************************************************************************/
+/*
+ Preferred version for commercial users who make use of memory pools.
+
+ This use of the sslKeys_t param implies this is for use in the MatrixSSL
+ product (input to matrixSslNewSession). However, we didn't want to
+ expose this API at the matrixSsl.h level due to the pool parameter. This
+ is strictly an API that commerical users will have access to
+*/
+int32 matrixX509ReadKeysEx(psPool_t *pool, sslKeys_t **keys,
+ const char *certFile, const char *privFile,
+ const char *privPass, const char *trustedCAFiles)
+{
+ sslKeys_t *lkeys;
+ unsigned char *privKeyMem;
+ int32 rc, privKeyMemLen;
+#ifdef USE_CLIENT_SIDE_SSL
+ sslCert_t *currCert, *prevCert = NULL;
+ unsigned char *caCert, *caStream;
+ sslChainLen_t chain;
+ int32 caCertLen, first, i;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ *keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
+ if (lkeys == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(lkeys, 0x0, sizeof(sslKeys_t));
+/*
+ Load certificate files. Any additional certificate files should chain
+ to the root CA held on the other side.
+*/
+ rc = readCertChain(pool, certFile, &lkeys->cert);
+ if (rc < 0 ) {
+ matrixRsaFreeKeys(lkeys);
+ return rc;
+ }
+/*
+ The first cert in certFile must be associated with the provided
+ private key.
+*/
+ if (privFile) {
+ rc = matrixX509ReadPrivKey(pool, privFile, privPass, &privKeyMem,
+ &privKeyMemLen);
+ if (rc < 0) {
+ matrixStrDebugMsg("Error reading private key file: %s\n",
+ (char*)privFile);
+ matrixRsaFreeKeys(lkeys);
+ return rc;
+ }
+ rc = matrixRsaParsePrivKey(pool, privKeyMem, privKeyMemLen,
+ &lkeys->cert.privKey);
+ if (rc < 0) {
+ matrixStrDebugMsg("Error parsing private key file: %s\n",
+ (char*)privFile);
+ psFree(privKeyMem);
+ matrixRsaFreeKeys(lkeys);
+ return rc;
+ }
+ psFree(privKeyMem);
+ }
+
+#ifdef USE_CLIENT_SIDE_SSL
+/*
+ Now deal with Certificate Authorities
+*/
+ if (trustedCAFiles != NULL) {
+ if (matrixX509ReadCert(pool, trustedCAFiles, &caCert, &caCertLen,
+ &chain) < 0 || caCert == NULL) {
+ matrixStrDebugMsg("Error reading CA cert files %s\n",
+ (char*)trustedCAFiles);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+
+ caStream = caCert;
+ i = first = 0;
+ while (chain[i] != 0) {
+/*
+ Don't allow one bad cert to ruin the whole bunch if possible
+*/
+ if (matrixX509ParseCert(pool, caStream, chain[i], &currCert) < 0) {
+ matrixX509FreeCert(currCert);
+ matrixStrDebugMsg("Error parsing CA cert %s\n",
+ (char*)trustedCAFiles);
+ caStream += chain[i]; caCertLen -= chain[i];
+ i++;
+ continue;
+ }
+
+ if (first == 0) {
+ lkeys->caCerts = currCert;
+ } else {
+ prevCert->next = currCert;
+ }
+ first++;
+ prevCert = currCert;
+ currCert = NULL;
+ caStream += chain[i]; caCertLen -= chain[i];
+ i++;
+ }
+ sslAssert(caCertLen == 0);
+ psFree(caCert);
+ }
+/*
+ Check to see that if a set of CAs were passed in at least
+ one ended up being valid.
+*/
+ if (trustedCAFiles != NULL && lkeys->caCerts == NULL) {
+ matrixStrDebugMsg("No valid CA certs in %s\n",
+ (char*)trustedCAFiles);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+#endif /* USE_CLIENT_SIDE_SSL */
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Public API to return a binary buffer from a cert. Suitable to send
+ * over the wire. Caller must free 'out' if this function returns success (0)
+ * Parse .pem files according to http://www.faqs.org/rfcs/rfc1421.html
+ */
+int32 matrixX509ReadCert(psPool_t *pool, const char *fileName,
+ unsigned char **out, int32 *outLen, sslChainLen_t *chain)
+{
+ int32 certBufLen, rc, certChainLen, i;
+ unsigned char *oneCert[MAX_CHAIN_LENGTH];
+ unsigned char *certPtr, *tmp;
+ char *certFile, *start, *end, *certBuf, *endTmp;
+ const char sep[] = ";";
+
+/*
+ Init chain array and output params
+*/
+ for (i=0; i < MAX_CHAIN_LENGTH; i++) {
+ oneCert[i] = NULL;
+ (*chain)[i] = 0;
+ }
+ *outLen = certChainLen = i = 0;
+ rc = -1;
+
+/*
+ For PKI product purposes, this routine now accepts a chain of certs.
+*/
+ if (fileName != NULL) {
+ fileName += parseList(pool, fileName, sep, &certFile);
+ } else {
+ return 0;
+ }
+
+ while (certFile != NULL) {
+
+ if (i == MAX_CHAIN_LENGTH) {
+ matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
+ MAX_CHAIN_LENGTH);
+ psFree(certFile);
+ rc = -1;
+ goto err;
+ }
+ if ((rc = psGetFileBin(pool, certFile, (unsigned char**)&certBuf,
+ &certBufLen)) < 0) {
+ matrixStrDebugMsg("Couldn't open file %s\n", certFile);
+ goto err;
+ }
+ psFree(certFile);
+ certPtr = (unsigned char*)certBuf;
+ start = end = endTmp = certBuf;
+
+ while (certBufLen > 0) {
+ if (((start = strstr(certBuf, "-----BEGIN")) != NULL) &&
+ ((start = strstr(certBuf, "CERTIFICATE-----")) != NULL) &&
+ ((end = strstr(start, "-----END")) != NULL) &&
+ ((endTmp = strstr(end,"CERTIFICATE-----")) != NULL)) {
+ start += strlen("CERTIFICATE-----");
+ (*chain)[i] = (int32)(end - start);
+ end = endTmp + strlen("CERTIFICATE-----");
+ while (*end == '\r' || *end == '\n' || *end == '\t'
+ || *end == ' ') {
+ end++;
+ }
+ } else {
+ psFree(certPtr);
+ rc = -1;
+ goto err;
+ }
+ oneCert[i] = psMalloc(pool, (*chain)[i]);
+ certBufLen -= (int32)(end - certBuf);
+ certBuf = end;
+ memset(oneCert[i], '\0', (*chain)[i]);
+
+ if (ps_base64_decode((unsigned char*)start, (*chain)[i], oneCert[i],
+ &(*chain)[i]) != 0) {
+ psFree(certPtr);
+ matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL);
+ rc = -1;
+ goto err;
+ }
+ certChainLen += (*chain)[i];
+ i++;
+ if (i == MAX_CHAIN_LENGTH) {
+ matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
+ MAX_CHAIN_LENGTH);
+ psFree(certPtr);
+ rc = -1;
+ goto err;
+ }
+ }
+ psFree(certPtr);
+/*
+ Check for more files
+*/
+ fileName += parseList(pool, fileName, sep, &certFile);
+ }
+
+ *outLen = certChainLen;
+/*
+ Don't bother stringing them together if only one was passed in
+*/
+ if (i == 1) {
+ sslAssert(certChainLen == (*chain)[0]);
+ *out = oneCert[0];
+ return 0;
+ } else {
+ *out = tmp = psMalloc(pool, certChainLen);
+ for (i=0; i < MAX_CHAIN_LENGTH; i++) {
+ if (oneCert[i]) {
+ memcpy(tmp, oneCert[i], (*chain)[i]);
+ tmp += (*chain)[i];
+ }
+ }
+ rc = 0;
+ }
+
+err:
+ for (i=0; i < MAX_CHAIN_LENGTH; i++) {
+ if (oneCert[i]) psFree(oneCert[i]);
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ This function was written strictly for clarity in the PeerSec crypto API
+ product. It extracts only the public key from a certificate file for use
+ in the lower level encrypt/decrypt RSA routines
+*/
+int32 matrixX509ReadPubKey(psPool_t *pool, const char *certFile,
+ sslRsaKey_t **key)
+{
+ unsigned char *certBuf;
+ sslChainLen_t chain;
+ int32 certBufLen;
+
+ certBuf = NULL;
+ if (matrixX509ReadCert(pool, certFile, &certBuf, &certBufLen, &chain) < 0) {
+ matrixStrDebugMsg("Unable to read certificate file %s\n",
+ (char*)certFile);
+ if (certBuf) psFree(certBuf);
+ return -1;
+ }
+ if (matrixX509ParsePubKey(pool, certBuf, certBufLen, key) < 0) {
+ psFree(certBuf);
+ return -1;
+ }
+ psFree(certBuf);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Allows for semi-colon delimited list of certificates for cert chaining.
+ Also allows multiple certificiates in a single file.
+
+ HOWERVER, in both cases the first in the list must be the identifying
+ cert of the application. Each subsequent cert is the parent of the previous
+*/
+int32 readCertChain(psPool_t *pool, const char *certFiles,
+ sslLocalCert_t *lkeys)
+{
+ sslLocalCert_t *currCert;
+ unsigned char *certBin, *tmp;
+ sslChainLen_t chain;
+ int32 certLen, i;
+
+ if (certFiles == NULL) {
+ return 0;
+ }
+
+ if (matrixX509ReadCert(pool, certFiles, &certBin, &certLen, &chain) < 0) {
+ matrixStrDebugMsg("Error reading cert file %s\n", (char*)certFiles);
+ return -1;
+ }
+/*
+ The first cert is allocated in the keys struct. All others in
+ linked list are allocated here.
+*/
+ i = 0;
+ tmp = certBin;
+ while (chain[i] != 0) {
+ if (i == 0) {
+ currCert = lkeys;
+ } else {
+ currCert->next = psMalloc(pool, sizeof(sslLocalCert_t));
+ if (currCert->next == NULL) {
+ psFree(tmp);
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(currCert->next, 0x0, sizeof(sslLocalCert_t));
+ currCert = currCert->next;
+ }
+ currCert->certBin = psMalloc(pool, chain[i]);
+ memcpy(currCert->certBin, certBin, chain[i]);
+ currCert->certLen = chain[i];
+ certBin += chain[i]; certLen -= chain[i];
+ i++;
+ }
+ psFree(tmp);
+ sslAssert(certLen == 0);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Strtok substitute
+ */
+static int32 parseList(psPool_t *pool, const char *list, const char *sep,
+ char **item)
+{
+ int32 start, listLen;
+ char *tmp;
+
+ start = listLen = (int32)strlen(list) + 1;
+ if (start == 1) {
+ *item = NULL;
+ return 0;
+ }
+ tmp = *item = psMalloc(pool, listLen);
+ if (tmp == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(*item, 0, listLen);
+ while (listLen > 0) {
+ if (*list == sep[0]) {
+ list++;
+ listLen--;
+ break;
+ }
+ if (*list == 0) {
+ break;
+ }
+ *tmp++ = *list++;
+ listLen--;
+ }
+ return start - listLen;
+}
+#endif /* USE_FILE_SYSTEM */
+
+
+/******************************************************************************/
+/*
+ Preferred version for commercial users who make use of memory pools.
+
+ This use of the sslKeys_t param implies this is for use in the MatrixSSL
+ product (input to matrixSslNewSession). However, we didn't want to
+ expose this API at the matrixSsl.h level due to the pool parameter. This
+ is strictly an API that commerical users will have access to.
+*/
+int32 matrixRsaParseKeysMem(psPool_t *pool, sslKeys_t **keys,
+ unsigned char *certBuf, int32 certLen, unsigned char *privBuf,
+ int32 privLen, unsigned char *trustedCABuf, int32 trustedCALen)
+{
+ sslKeys_t *lkeys;
+ sslLocalCert_t *current, *next;
+ unsigned char *binPtr;
+ int32 len, lenOh, i;
+#ifdef USE_CLIENT_SIDE_SSL
+ sslCert_t *currentCA, *nextCA;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ *keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
+ if (lkeys == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(lkeys, 0x0, sizeof(sslKeys_t));
+/*
+ The buffers are just the ASN.1 streams so the intermediate parse
+ that used to be here is gone. Doing a straight memcpy for this
+ and passing that along to X509ParseCert
+*/
+ i = 0;
+ current = &lkeys->cert;
+ binPtr = certBuf;
+/*
+ Need to check for a chain here. Only way to do this is to read off the
+ length id from the DER stream for each. The chain must be just a stream
+ of DER certs with the child-most cert always first.
+*/
+ while (certLen > 0) {
+ if (getSequence(&certBuf, certLen, &len) < 0) {
+ matrixStrDebugMsg("Unable to parse length of cert stream\n", NULL);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+/*
+ Account for the overhead of storing the length itself
+*/
+ lenOh = (int32)(certBuf - binPtr);
+ len += lenOh;
+ certBuf -= lenOh;
+/*
+ First cert is already malloced
+*/
+ if (i > 0) {
+ next = psMalloc(pool, sizeof(sslLocalCert_t));
+ memset(next, 0x0, sizeof(sslLocalCert_t));
+ current->next = next;
+ current = next;
+ }
+ current->certBin = psMalloc(pool, len);
+ memcpy(current->certBin, certBuf, len);
+ current->certLen = len;
+ certLen -= len;
+ certBuf += len;
+ binPtr = certBuf;
+ i++;
+ }
+
+/*
+ Parse private key
+*/
+ if (privLen > 0) {
+ if (matrixRsaParsePrivKey(pool, privBuf, privLen,
+ &lkeys->cert.privKey) < 0) {
+ matrixStrDebugMsg("Error reading private key mem\n", NULL);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+ }
+
+
+/*
+ Trusted CAs
+*/
+#ifdef USE_CLIENT_SIDE_SSL
+ if (trustedCABuf != NULL && trustedCALen > 0) {
+ i = 0;
+ binPtr = trustedCABuf;
+ currentCA = NULL;
+/*
+ Need to check for list here. Only way to do this is to read off the
+ length id from the DER stream for each.
+*/
+ while (trustedCALen > 0) {
+ if (getSequence(&trustedCABuf, trustedCALen, &len) < 0) {
+ matrixStrDebugMsg("Unable to parse length of CA stream\n",
+ NULL);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+/*
+ Account for the overhead of storing the length itself
+*/
+ lenOh = (int32)(trustedCABuf - binPtr);
+ len += lenOh;
+ trustedCABuf -= lenOh;
+
+ if (matrixX509ParseCert(pool, trustedCABuf, len, &currentCA) < 0) {
+ matrixX509FreeCert(currentCA);
+ matrixStrDebugMsg("Error parsing CA cert\n", NULL);
+ matrixRsaFreeKeys(lkeys);
+ return -1;
+ }
+/*
+ First cert should be assigned to lkeys
+*/
+ if (i == 0) {
+ lkeys->caCerts = currentCA;
+ nextCA = lkeys->caCerts;
+ } else {
+ nextCA->next = currentCA;
+ nextCA = currentCA;
+ }
+ currentCA = currentCA->next;
+ trustedCALen -= len;
+ trustedCABuf += len;
+ binPtr = trustedCABuf;
+ i++;
+ }
+ }
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ In-memory version of matrixX509ReadPubKey.
+ This function was written strictly for clarity in the PeerSec crypto API
+ subset. It extracts only the public key from a certificate file for use
+ in the lower level encrypt/decrypt RSA routines.
+*/
+int32 matrixX509ParsePubKey(psPool_t *pool, unsigned char *certBuf,
+ int32 certLen, sslRsaKey_t **key)
+{
+ sslRsaKey_t *lkey;
+ sslCert_t *certStruct;
+ int32 err;
+
+ if (matrixX509ParseCert(pool, certBuf, certLen, &certStruct) < 0) {
+ matrixX509FreeCert(certStruct);
+ return -1;
+ }
+ lkey = *key = psMalloc(pool, sizeof(sslRsaKey_t));
+ memset(lkey, 0x0, sizeof(sslRsaKey_t));
+
+ if ((err = _mp_init_multi(pool, &lkey->e, &lkey->N, NULL,
+ NULL, NULL, NULL, NULL, NULL)) != MP_OKAY) {
+ matrixX509FreeCert(certStruct);
+ psFree(lkey);
+ return err;
+ }
+ mp_copy(&certStruct->publicKey.e, &lkey->e);
+ mp_copy(&certStruct->publicKey.N, &lkey->N);
+
+ mp_shrink(&lkey->e);
+ mp_shrink(&lkey->N);
+
+ lkey->size = certStruct->publicKey.size;
+
+ matrixX509FreeCert(certStruct);
+
+ 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,
+ sslCert_t **outcert)
+{
+ sslCert_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(sslCert_t));
+ if (cert == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(cert, '\0', sizeof(sslCert_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 support@peersec.com\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(sslCert_t));
+ cert = cert->next;
+ memset(cert, '\0', sizeof(sslCert_t));
+ } else {
+ parsing = 0;
+ }
+ }
+
+ return (int32)(p - pp);
+}
+
+/******************************************************************************/
+/*
+ User must call after all calls to matrixX509ParseCert
+ (we violate the coding standard a bit here for clarity)
+*/
+void matrixX509FreeCert(sslCert_t *cert)
+{
+ sslCert_t *curr, *next;
+ sslSubjectAltName_t *active, *inc;
+
+ curr = cert;
+ while (curr) {
+ psFreeDNStruct(&curr->issuer);
+ psFreeDNStruct(&curr->subject);
+ if (curr->serialNumber) psFree(curr->serialNumber);
+ if (curr->notBefore) psFree(curr->notBefore);
+ if (curr->notAfter) psFree(curr->notAfter);
+ if (curr->publicKey.N.dp) mp_clear(&(curr->publicKey.N));
+ if (curr->publicKey.e.dp) mp_clear(&(curr->publicKey.e));
+ if (curr->signature) psFree(curr->signature);
+ if (curr->uniqueUserId) psFree(curr->uniqueUserId);
+ if (curr->uniqueSubjectId) psFree(curr->uniqueSubjectId);
+
+ if (curr->extensions.san) {
+ active = curr->extensions.san;
+ while (active != NULL) {
+ inc = active->next;
+ psFree(active->data);
+ psFree(active);
+ active = inc;
+ }
+ }
+
+
+#ifdef USE_FULL_CERT_PARSE
+ if (curr->extensions.keyUsage) psFree(curr->extensions.keyUsage);
+ if (curr->extensions.sk.id) psFree(curr->extensions.sk.id);
+ if (curr->extensions.ak.keyId) psFree(curr->extensions.ak.keyId);
+ if (curr->extensions.ak.serialNum)
+ psFree(curr->extensions.ak.serialNum);
+ if (curr->extensions.ak.attribs.commonName)
+ psFree(curr->extensions.ak.attribs.commonName);
+ if (curr->extensions.ak.attribs.country)
+ psFree(curr->extensions.ak.attribs.country);
+ if (curr->extensions.ak.attribs.state)
+ psFree(curr->extensions.ak.attribs.state);
+ if (curr->extensions.ak.attribs.locality)
+ psFree(curr->extensions.ak.attribs.locality);
+ if (curr->extensions.ak.attribs.organization)
+ psFree(curr->extensions.ak.attribs.organization);
+ if (curr->extensions.ak.attribs.orgUnit)
+ psFree(curr->extensions.ak.attribs.orgUnit);
+#endif /* SSL_FULL_CERT_PARSE */
+ next = curr->next;
+ psFree(curr);
+ curr = next;
+ }
+}
+
+/******************************************************************************/
+/*
+ Do the signature validation for a subject certificate against a
+ known CA certificate
+*/
+int32 psAsnConfirmSignature(unsigned char *sigHash, unsigned char *sigOut,
+ int32 sigLen)
+{
+ unsigned char *end, *p = sigOut;
+ unsigned char hash[SSL_SHA1_HASH_SIZE];
+ int32 len, oi;
+
+ end = p + sigLen;
+/*
+ DigestInfo ::= SEQUENCE {
+ digestAlgorithm DigestAlgorithmIdentifier,
+ digest Digest }
+
+ DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+
+ Digest ::= OCTET STRING
+*/
+ if (getSequence(&p, (int32)(end - p), &len) < 0) {
+ return -1;
+ }
+
+/*
+ Could be MD5 or SHA1
+ */
+ if (getAlgorithmIdentifier(&p, (int32)(end - p), &oi, 0) < 0) {
+ return -1;
+ }
+ if ((*p++ != ASN_OCTET_STRING) ||
+ asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) < len) {
+ return -1;
+ }
+ memcpy(hash, p, len);
+ if (oi == OID_MD5 || oi == OID_MD2) {
+ if (len != SSL_MD5_HASH_SIZE) {
+ return -1;
+ }
+ } else if (oi == OID_SHA1) {
+ if (len != SSL_SHA1_HASH_SIZE) {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+/*
+ hash should match sigHash
+*/
+ if (memcmp(hash, sigHash, len) != 0) {
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Extension lookup
+*/
+static int32 lookupExt(unsigned char md5hash[SSL_MD5_HASH_SIZE])
+{
+ int32 i, j;
+ const unsigned char *tmp;
+
+ for (i = 0; ;i++) {
+ if (extTable[i].id == -1) {
+ return -1;
+ }
+ tmp = extTable[i].hash;
+ for (j = 0; j < SSL_MD5_HASH_SIZE; j++) {
+ if (md5hash[j] != tmp[j]) {
+ break;
+ }
+ if (j == SSL_MD5_HASH_SIZE - 1) {
+ return extTable[i].id;
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+/*
+ 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, critical, fullExtLen;
+ unsigned char oid[SSL_MD5_HASH_SIZE];
+ sslMd5Context_t md5ctx;
+ sslSubjectAltName_t *activeName, *prevName;
+
+ 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;
+ }
+/*
+ Have seen some certs that don't include a cA bool.
+*/
+ if (*p == ASN_BOOLEAN) {
+ p++;
+ if (*p++ != 1) {
+ return -1;
+ }
+ extensions->bc.ca = *p++;
+ } else {
+ extensions->bc.ca = 0;
+ }
+/*
+ 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 (extensions->san == NULL) {
+ activeName = extensions->san = psMalloc(pool,
+ sizeof(sslSubjectAltName_t));
+ } else {
+/*
+ Find the end
+*/
+ prevName = extensions->san;
+ activeName = prevName->next;
+ while (activeName != NULL) {
+ prevName = activeName;
+ activeName = prevName->next;
+ }
+ prevName->next = psMalloc(pool,
+ sizeof(sslSubjectAltName_t));
+ activeName = prevName->next;
+ }
+ activeName->next = NULL;
+ activeName->data = NULL;
+ memset(activeName->name, '\0', 16);
+
+ activeName->id = *p & 0xF;
+ switch (activeName->id) {
+ case 0:
+ memcpy(activeName->name, "other", 5);
+ break;
+ case 1:
+ memcpy(activeName->name, "email", 5);
+ break;
+ case 2:
+ memcpy(activeName->name, "DNS", 3);
+ break;
+ case 3:
+ memcpy(activeName->name, "x400Address", 11);
+ break;
+ case 4:
+ memcpy(activeName->name, "directoryName", 13);
+ break;
+ case 5:
+ memcpy(activeName->name, "ediPartyName", 12);
+ break;
+ case 6:
+ memcpy(activeName->name, "URI", 3);
+ break;
+ case 7:
+ memcpy(activeName->name, "iPAddress", 9);
+ break;
+ case 8:
+ memcpy(activeName->name, "registeredID", 12);
+ break;
+ default:
+ memcpy(activeName->name, "unknown", 7);
+ break;
+ }
+
+ p++;
+ activeName->dataLen = *p++;
+ if (extEnd - p < activeName->dataLen) {
+ return -1;
+ }
+ activeName->data = psMalloc(pool, activeName->dataLen + 1);
+ if (activeName->data == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(activeName->data, 0x0, activeName->dataLen + 1);
+ memcpy(activeName->data, p, activeName->dataLen);
+
+ p = p + activeName->dataLen;
+ /* the magic 2 is the type and length */
+ len -= activeName->dataLen + 2;
+ }
+ 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;
+ }
+/*
+ We'd expect a length of 3 with the first byte being '07' to
+ account for the trailing ignore bits in the second byte.
+ But it doesn't appear all certificates adhere to the ASN.1
+ encoding standard very closely. Just set it all aside for
+ user to interpret as necessary.
+*/
+ extensions->keyUsage = psMalloc(pool, len);
+ memcpy(extensions->keyUsage, p, len);
+ extensions->keyUsageLen = len;
+ 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;
+}
+
+/******************************************************************************/
+/*
+ Walk through the certificate chain and validate it. Return the final
+ member of the chain as the subjectCert that can then be validated against
+ the CAs. The subjectCert points into the chain param (no need to free)
+*/
+int32 matrixX509ValidateCertChain(psPool_t *pool, sslCert_t *chain,
+ sslCert_t **subjectCert, int32 *valid)
+{
+ sslCert_t *ic;
+
+ *subjectCert = chain;
+ *valid = 1;
+ while ((*subjectCert)->next != NULL) {
+ ic = (*subjectCert)->next;
+ if (matrixX509ValidateCertInternal(pool, *subjectCert, ic, 1) < 0) {
+ *valid = -1;
+ return -1;
+ }
+/*
+ If any portion is invalid, it's all invalid
+*/
+ if ((*subjectCert)->valid != 1) {
+ *valid = -1;
+ }
+ *subjectCert = (*subjectCert)->next;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ A signature validation for certificates. -1 return is an error. The success
+ of the validation is returned in the 'valid' param of the subjectCert.
+ 1 if the issuerCert signed the subject cert. -1 if not
+*/
+int32 matrixX509ValidateCert(psPool_t *pool, sslCert_t *subjectCert,
+ sslCert_t *issuerCert, int32 *valid)
+{
+ if (matrixX509ValidateCertInternal(pool, subjectCert, issuerCert, 0) < 0) {
+ *valid = -1;
+ return -1;
+ }
+ *valid = subjectCert->valid;
+ return 0;
+}
+
+static int32 matrixX509ValidateCertInternal(psPool_t *pool,
+ sslCert_t *subjectCert, sslCert_t *issuerCert, int32 chain)
+{
+ sslCert_t *ic;
+ unsigned char sigOut[10 + SSL_SHA1_HASH_SIZE + 5]; /* See below */
+ int32 sigLen, sigType, rc;
+
+ subjectCert->valid = -1;
+/*
+ Supporting a one level chain or a self-signed cert. If the issuer
+ is NULL, the self-signed test is done.
+*/
+ if (issuerCert == NULL) {
+ matrixStrDebugMsg("Warning: No CA to validate cert with\n", NULL);
+ matrixStrDebugMsg("\tPerforming self-signed CA test\n", NULL);
+ ic = subjectCert;
+ } else {
+ ic = issuerCert;
+ }
+/*
+ Path confirmation. If this is a chain verification, do not allow
+ any holes in the path. Error out if issuer does not have CA permissions
+ or if hashes do not match anywhere along the way.
+*/
+ while (ic) {
+ if (subjectCert != ic) {
+/*
+ Certificate authority constraint only available in version 3 certs
+*/
+ if ((ic->version > 1) && (ic->extensions.bc.ca <= 0)) {
+ if (chain) {
+ return -1;
+ }
+ ic = ic->next;
+ continue;
+ }
+/*
+ Use sha1 hash of issuer fields computed at parse time to compare
+*/
+ if (memcmp(subjectCert->issuer.hash, ic->subject.hash,
+ SSL_SHA1_HASH_SIZE) != 0) {
+ if (chain) {
+ return -1;
+ }
+ ic = ic->next;
+ continue;
+ }
+ }
+/*
+ Signature confirmation
+ The sigLen is the ASN.1 size in bytes for encoding the hash.
+ The magic 10 is comprised of the SEQUENCE and ALGORITHM ID overhead.
+ The magic 8 and 5 are the OID lengths of the corresponding algorithm.
+ NOTE: if sigLen is modified, above sigOut static size must be changed
+*/
+ if (subjectCert->sigAlgorithm == OID_RSA_MD5 ||
+ subjectCert->sigAlgorithm == OID_RSA_MD2) {
+ sigType = RSA_SIG;
+ sigLen = 10 + SSL_MD5_HASH_SIZE + 8; /* See above */
+ } else if (subjectCert->sigAlgorithm == OID_RSA_SHA1) {
+ sigLen = 10 + SSL_SHA1_HASH_SIZE + 5; /* See above */
+ sigType = RSA_SIG;
+ } else {
+ matrixStrDebugMsg("Unsupported signature algorithm\n", NULL);
+ return -1;
+ }
+
+ if (sigType == RSA_SIG) {
+ sslAssert(sigLen <= sizeof(sigOut));
+
+ if (matrixRsaDecryptPub(pool, &(ic->publicKey),
+ subjectCert->signature, subjectCert->signatureLen, sigOut,
+ sigLen) < 0) {
+ matrixStrDebugMsg("Unable to RSA decrypt signature\n", NULL);
+ return -1;
+ }
+ rc = psAsnConfirmSignature(subjectCert->sigHash, sigOut, sigLen);
+ }
+/*
+ If this is a chain test, fail on any gaps in the chain
+*/
+ if (rc < 0) {
+ if (chain) {
+ return -1;
+ }
+ ic = ic->next;
+ continue;
+ }
+/*
+ Fall through to here only if passed signature check.
+*/
+ subjectCert->valid = 1;
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Calls a user defined callback to allow for manual validation of the
+ certificate.
+*/
+int32 matrixX509UserValidator(psPool_t *pool, sslCert_t *subjectCert,
+ int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg)
+{
+ sslCertInfo_t *cert, *current, *next;
+ int32 rc;
+
+ if (certValidator == NULL) {
+ return 0;
+ }
+/*
+ Pass the entire certificate chain to the user callback.
+*/
+ current = cert = psMalloc(pool, sizeof(sslCertInfo_t));
+ if (current == NULL) {
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(cert, 0x0, sizeof(sslCertInfo_t));
+ while (subjectCert) {
+
+ current->issuer.commonName = subjectCert->issuer.commonName;
+ current->issuer.country = subjectCert->issuer.country;
+ current->issuer.locality = subjectCert->issuer.locality;
+ current->issuer.organization = subjectCert->issuer.organization;
+ current->issuer.orgUnit = subjectCert->issuer.orgUnit;
+ current->issuer.state = subjectCert->issuer.state;
+
+ current->subject.commonName = subjectCert->subject.commonName;
+ current->subject.country = subjectCert->subject.country;
+ current->subject.locality = subjectCert->subject.locality;
+ current->subject.organization = subjectCert->subject.organization;
+ current->subject.orgUnit = subjectCert->subject.orgUnit;
+ current->subject.state = subjectCert->subject.state;
+
+ current->serialNumber = subjectCert->serialNumber;
+ current->serialNumberLen = subjectCert->serialNumberLen;
+ current->verified = subjectCert->valid;
+ current->notBefore = subjectCert->notBefore;
+ current->notAfter = subjectCert->notAfter;
+
+ current->subjectAltName = subjectCert->extensions.san;
+
+ if (subjectCert->certAlgorithm == OID_RSA_MD5 ||
+ subjectCert->certAlgorithm == OID_RSA_MD2) {
+ current->sigHashLen = SSL_MD5_HASH_SIZE;
+ } else if (subjectCert->certAlgorithm == OID_RSA_SHA1) {
+ current->sigHashLen = SSL_SHA1_HASH_SIZE;
+ }
+ current->sigHash = (char*)subjectCert->sigHash;
+ if (subjectCert->next) {
+ next = psMalloc(pool, sizeof(sslCertInfo_t));
+ if (next == NULL) {
+ while (cert) {
+ next = cert->next;
+ psFree(cert);
+ cert = next;
+ }
+ return -8; /* SSL_MEM_ERROR */
+ }
+ memset(next, 0x0, sizeof(sslCertInfo_t));
+ current->next = next;
+ current = next;
+ }
+ subjectCert = subjectCert->next;
+ }
+/*
+ The user callback
+*/
+ rc = certValidator(cert, arg);
+/*
+ Free the chain
+*/
+ while (cert) {
+ next = cert->next;
+ psFree(cert);
+ cert = next;
+ }
+ return rc;
+}
+#endif /* USE_X509 */
+#endif /* USE_RSA */
+
+
+/******************************************************************************/
+
+
diff --git a/contrib/libs/matrixssl/src/sslDecode.c b/contrib/libs/matrixssl/src/sslDecode.c
new file mode 100644
index 00000000000..a103280d024
--- /dev/null
+++ b/contrib/libs/matrixssl/src/sslDecode.c
@@ -0,0 +1,1387 @@
+/*
+ * sslDecode.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Secure Sockets Layer message decoding
+ */
+/*
+ * 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 "matrixInternal.h"
+
+/******************************************************************************/
+
+#define SSL_MAX_IGNORED_MESSAGE_COUNT 1024
+
+static int32 parseSSLHandshake(ssl_t *ssl, char *inbuf, int32 len);
+static int32 parseSingleCert(ssl_t *ssl, unsigned char *c, unsigned char *end,
+ int32 certLen);
+
+/******************************************************************************/
+/*
+ Parse incoming data per http://wp.netscape.com/eng/ssl3
+*/
+int32 matrixSslDecode(ssl_t *ssl, sslBuf_t *in, sslBuf_t *out,
+ unsigned char *error, unsigned char *alertLevel,
+ unsigned char *alertDescription)
+{
+ unsigned char *c, *p, *end, *pend, *oend;
+ unsigned char *mac, macError;
+ int32 rc;
+ unsigned char padLen;
+/*
+ If we've had a protocol error, don't allow further use of the session
+*/
+ *error = SSL_ALERT_NONE;
+ if (ssl->flags & SSL_FLAGS_ERROR || ssl->flags & SSL_FLAGS_CLOSED) {
+ return SSL_ERROR;
+ }
+/*
+ This flag is set if the previous call to this routine returned an SSL_FULL
+ error from encodeResponse, indicating that there is data to be encoded,
+ but the out buffer was not big enough to handle it. If we fall in this
+ case, the user has increased the out buffer size and is re-calling this
+ routine
+*/
+ if (ssl->flags & SSL_FLAGS_NEED_ENCODE) {
+ ssl->flags &= ~SSL_FLAGS_NEED_ENCODE;
+ goto encodeResponse;
+ }
+
+ c = in->start;
+ end = in->end;
+ oend = out->end;
+/*
+ Processing the SSL Record header:
+ If the high bit of the first byte is set and this is the first
+ message we've seen, we parse the request as an SSLv2 request
+ http://wp.netscape.com/eng/security/SSL_2.html
+ SSLv2 also supports a 3 byte header when padding is used, but this should
+ not be required for the initial plaintext message, so we don't support it
+ v3 Header:
+ 1 byte type
+ 1 byte major version
+ 1 byte minor version
+ 2 bytes length
+ v2 Header
+ 2 bytes length (ignore high bit)
+*/
+decodeMore:
+ sslAssert(out->end == oend);
+ if (end - c == 0) {
+/*
+ This case could happen if change cipher spec was last
+ message in the buffer
+*/
+ return SSL_SUCCESS;
+ }
+
+ if (end - c < SSL2_HEADER_LEN) {
+ return SSL_PARTIAL;
+ }
+ if (ssl->majVer != 0 || (*c & 0x80) == 0) {
+ if (end - c < ssl->recordHeadLen) {
+ return SSL_PARTIAL;
+ }
+ ssl->rec.type = *c; c++;
+ ssl->rec.majVer = *c; c++;
+ ssl->rec.minVer = *c; c++;
+ ssl->rec.len = *c << 8; c++;
+ ssl->rec.len += *c; c++;
+ } else {
+ ssl->rec.type = SSL_RECORD_TYPE_HANDSHAKE;
+ ssl->rec.majVer = 2;
+ ssl->rec.minVer = 0;
+ ssl->rec.len = (*c & 0x7f) << 8; c++;
+ ssl->rec.len += *c; c++;
+ }
+/*
+ Validate the various record headers. The type must be valid,
+ the major and minor versions must match the negotiated versions (if we're
+ past ClientHello) and the length must be < 16K and > 0
+*/
+ if (ssl->rec.type != SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC &&
+ ssl->rec.type != SSL_RECORD_TYPE_ALERT &&
+ ssl->rec.type != SSL_RECORD_TYPE_HANDSHAKE &&
+ ssl->rec.type != SSL_RECORD_TYPE_APPLICATION_DATA) {
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ matrixIntDebugMsg("Record header type not valid: %d\n", ssl->rec.type);
+ goto encodeResponse;
+ }
+
+/*
+ Verify the record version numbers unless this is the first record we're
+ reading.
+*/
+ if (ssl->hsState != SSL_HS_SERVER_HELLO &&
+ ssl->hsState != SSL_HS_CLIENT_HELLO) {
+ if (ssl->rec.majVer != ssl->majVer || ssl->rec.minVer != ssl->minVer) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Record header version not valid\n", NULL);
+ goto encodeResponse;
+ }
+ }
+/*
+ Verify max and min record lengths
+*/
+ if (ssl->rec.len > SSL_MAX_RECORD_LEN || ssl->rec.len == 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixIntDebugMsg("Record header length not valid: %d\n", ssl->rec.len);
+ goto encodeResponse;
+ }
+/*
+ This implementation requires the entire SSL record to be in the 'in' buffer
+ before we parse it. This is because we need to MAC the entire record before
+ allowing it to be used by the caller. The only alternative would be to
+ copy the partial record to an internal buffer, but that would require more
+ memory usage, which we're trying to keep low.
+*/
+ if (end - c < ssl->rec.len) {
+ return SSL_PARTIAL;
+ }
+
+/*
+ Make sure we have enough room to hold the decoded record
+*/
+ if ((out->buf + out->size) - out->end < ssl->rec.len) {
+ return SSL_FULL;
+ }
+
+/*
+ Decrypt the entire record contents. The record length should be
+ a multiple of block size, or decrypt will return an error
+ If we're still handshaking and sending plaintext, the decryption
+ callback will point to a null provider that passes the data unchanged
+*/
+ if (ssl->decrypt(&ssl->sec.decryptCtx, c, out->end, ssl->rec.len) < 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ goto encodeResponse;
+ }
+ c += ssl->rec.len;
+/*
+ If we're reading a secure message, we need to validate the MAC and
+ padding (if using a block cipher). Insecure messages do not have
+ a trailing MAC or any padding.
+
+ SECURITY - There are several vulnerabilities in block cipher padding
+ that we handle in the below code. For more information see:
+ http://www.openssl.org/~bodo/tls-cbc.txt
+*/
+ if (ssl->flags & SSL_FLAGS_READ_SECURE) {
+/*
+ Verify the record is at least as big as the MAC
+ Start tracking MAC errors, rather then immediately catching them to
+ stop timing and alert description attacks that differentiate between
+ a padding error and a MAC error.
+*/
+ if (ssl->rec.len < ssl->deMacSize) {
+ ssl->err = SSL_ALERT_BAD_RECORD_MAC;
+ matrixStrDebugMsg("Record length too short for MAC\n", NULL);
+ goto encodeResponse;
+ }
+ macError = 0;
+/*
+ Decode padding only if blocksize is > 0 (we're using a block cipher),
+ otherwise no padding will be present, and the mac is the last
+ macSize bytes of the record.
+*/
+ if (ssl->deBlockSize <= 1) {
+ mac = out->end + ssl->rec.len - ssl->deMacSize;
+ } else {
+/*
+ Verify the pad data for block ciphers
+ c points within the cipher text, p points within the plaintext
+ The last byte of the record is the pad length
+*/
+ p = out->end + ssl->rec.len;
+ padLen = *(p - 1);
+/*
+ SSL3.0 requires the pad length to be less than blockSize
+ TLS can have a pad length up to 255 for obfuscating the data len
+*/
+ if (ssl->majVer == SSL3_MAJ_VER && ssl->minVer == SSL3_MIN_VER &&
+ padLen >= ssl->deBlockSize) {
+ macError++;
+ }
+/*
+ The minimum record length is the size of the mac, plus pad bytes
+ plus one length byte
+*/
+ if (ssl->rec.len < ssl->deMacSize + padLen + 1) {
+ macError++;
+ }
+/*
+ The mac starts macSize bytes before the padding and length byte.
+ If we have a macError, just fake the mac as the last macSize bytes
+ of the record, so we are sure to have enough bytes to verify
+ against, we'll fail anyway, so the actual contents don't matter.
+*/
+ if (!macError) {
+ mac = p - padLen - 1 - ssl->deMacSize;
+ } else {
+ mac = out->end + ssl->rec.len - ssl->deMacSize;
+ }
+ }
+/*
+ Verify the MAC of the message by calculating our own MAC of the message
+ and comparing it to the one in the message. We do this step regardless
+ of whether or not we've already set macError to stop timing attacks.
+ Clear the mac in the callers buffer if we're successful
+*/
+ if (ssl->verifyMac(ssl, ssl->rec.type, out->end,
+ (int32)(mac - out->end), mac) < 0 || macError) {
+ ssl->err = SSL_ALERT_BAD_RECORD_MAC;
+ matrixStrDebugMsg("Couldn't verify MAC or pad of record data\n",
+ NULL);
+ goto encodeResponse;
+ }
+ memset(mac, 0x0, ssl->deMacSize);
+/*
+ Record data starts at out->end and ends at mac
+*/
+ p = out->end;
+ pend = mac;
+ } else {
+/*
+ The record data is the entire record as there is no MAC or padding
+*/
+ p = out->end;
+ pend = mac = out->end + ssl->rec.len;
+ }
+/*
+ Check now for maximum plaintext length of 16kb. No appropriate
+ SSL alert for this
+*/
+ if ((int32)(pend - p) > SSL_MAX_PLAINTEXT_LEN) {
+ ssl->err = SSL_ALERT_BAD_RECORD_MAC;
+ matrixStrDebugMsg("Record overflow\n", NULL);
+ goto encodeResponse;
+ }
+
+/*
+ Take action based on the actual record type we're dealing with
+ 'p' points to the start of the data, and 'pend' points to the end
+*/
+ switch (ssl->rec.type) {
+ case SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC:
+/*
+ Body is single byte with value 1 to indicate that the next message
+ will be encrypted using the negotiated cipher suite
+*/
+ if (pend - p < 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid length for CipherSpec\n", NULL);
+ goto encodeResponse;
+ }
+ if (*p == 1) {
+ p++;
+ } else {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid value for CipherSpec\n", NULL);
+ goto encodeResponse;
+ }
+
+/*
+ If we're expecting finished, then this is the right place to get
+ this record. It is really part of the handshake but it has its
+ own record type.
+ Activate the read cipher callbacks, so we will decrypt incoming
+ data from now on.
+*/
+ if (ssl->hsState == SSL_HS_FINISHED) {
+ sslActivateReadCipher(ssl);
+ } else {
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ matrixIntDebugMsg("Invalid CipherSpec order: %d\n", ssl->hsState);
+ goto encodeResponse;
+ }
+ in->start = c;
+ goto decodeMore;
+
+ case SSL_RECORD_TYPE_ALERT:
+/*
+ 1 byte alert level (warning or fatal)
+ 1 byte alert description corresponding to SSL_ALERT_*
+*/
+ if (pend - p < 2) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Error in length of alert record\n", NULL);
+ goto encodeResponse;
+ }
+ *alertLevel = *p; p++;
+ *alertDescription = *p; p++;
+/*
+ If the alert is fatal, or is a close message (usually a warning),
+ flag the session with ERROR so it cannot be used anymore.
+ Caller can decide whether or not to close on other warnings.
+*/
+ if (*alertLevel == SSL_ALERT_LEVEL_FATAL) {
+ ssl->flags |= SSL_FLAGS_ERROR;
+ }
+ if (*alertDescription == SSL_ALERT_CLOSE_NOTIFY) {
+ ssl->flags |= SSL_FLAGS_CLOSED;
+ }
+ in->start = c;
+ return SSL_ALERT;
+
+ case SSL_RECORD_TYPE_HANDSHAKE:
+/*
+ We've got one or more handshake messages in the record data.
+ The handshake parsing function will take care of all messages
+ and return an error if there is any problem.
+ If there is a response to be sent (either a return handshake
+ or an error alert, send it). If the message was parsed, but no
+ response is needed, loop up and try to parse another message
+*/
+ rc = parseSSLHandshake(ssl, (char*)p, (int32)(pend - p));
+ switch (rc) {
+ case SSL_SUCCESS:
+ in->start = c;
+ return SSL_SUCCESS;
+ case SSL_PROCESS_DATA:
+ in->start = c;
+ goto encodeResponse;
+ case SSL_ERROR:
+ if (ssl->err == SSL_ALERT_NONE) {
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ }
+ goto encodeResponse;
+ }
+ break;
+
+ case SSL_RECORD_TYPE_APPLICATION_DATA:
+/*
+ Data is in the out buffer, let user handle it
+ Don't allow application data until handshake is complete, and we are
+ secure. It is ok to let application data through on the client
+ if we are in the SERVER_HELLO state because this could mean that
+ the client has sent a CLIENT_HELLO message for a rehandshake
+ and is awaiting reply.
+*/
+ if ((ssl->hsState != SSL_HS_DONE && ssl->hsState != SSL_HS_SERVER_HELLO)
+ || !(ssl->flags & SSL_FLAGS_READ_SECURE)) {
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ matrixIntDebugMsg("Incomplete handshake: %d\n", ssl->hsState);
+ goto encodeResponse;
+ }
+/*
+ SECURITY - If the mac is at the current out->end, then there is no data
+ in the record. These records are valid, but are usually not sent by
+ the application layer protocol. Rather, they are initiated within the
+ remote SSL protocol implementation to avoid some types of attacks when
+ using block ciphers. For more information see:
+ http://www.openssl.org/~bodo/tls-cbc.txt
+
+ We eat these records here rather than passing them on to the caller.
+ The rationale behind this is that if the caller's application protocol
+ is depending on zero length SSL messages, it will fail anyway if some of
+ those messages are initiated within the SSL protocol layer. Also
+ this clears up any confusion where the caller might interpret a zero
+ length read as an end of file (EOF) or would block (EWOULDBLOCK) type
+ scenario.
+
+ SECURITY - Looping back up and ignoring the message has the potential
+ for denial of service, because we are not changing the state of the
+ system in any way when processing these messages. To counteract this,
+ we maintain a counter that we share with other types of ignored messages
+*/
+ in->start = c;
+ if (out->end == mac) {
+ if (ssl->ignoredMessageCount++ < SSL_MAX_IGNORED_MESSAGE_COUNT) {
+ goto decodeMore;
+ }
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ matrixIntDebugMsg("Exceeded limit on ignored messages: %d\n",
+ SSL_MAX_IGNORED_MESSAGE_COUNT);
+ goto encodeResponse;
+ }
+ if (ssl->ignoredMessageCount > 0) {
+ ssl->ignoredMessageCount--;
+ }
+ out->end = mac;
+ return SSL_PROCESS_DATA;
+ }
+/*
+ Should not get here
+*/
+ matrixIntDebugMsg("Invalid record type in matrixSslDecode: %d\n",
+ ssl->rec.type);
+ return SSL_ERROR;
+
+encodeResponse:
+/*
+ We decoded a record that needs a response, either a handshake response
+ or an alert if we've detected an error.
+
+ SECURITY - Clear the decoded incoming record from outbuf before encoding
+ the response into outbuf. rec.len could be invalid, clear the minimum
+ of rec.len and remaining outbuf size
+*/
+ rc = min (ssl->rec.len, (int32)((out->buf + out->size) - out->end));
+ if (rc > 0) {
+ memset(out->end, 0x0, rc);
+ }
+ if (ssl->hsState == SSL_HS_HELLO_REQUEST) {
+/*
+ Don't clear the session info. If receiving a HELLO_REQUEST from a
+ MatrixSSL enabled server the determination on whether to reuse the
+ session is made on that side, so always send the current session
+*/
+ rc = matrixSslEncodeClientHello(ssl, out, ssl->cipher->id);
+ } else {
+ rc = sslEncodeResponse(ssl, out);
+ }
+ if (rc == SSL_SUCCESS) {
+ if (ssl->err != SSL_ALERT_NONE) {
+ *error = (unsigned char)ssl->err;
+ ssl->flags |= SSL_FLAGS_ERROR;
+ return SSL_ERROR;
+ }
+ return SSL_SEND_RESPONSE;
+ }
+ if (rc == SSL_FULL) {
+ ssl->flags |= SSL_FLAGS_NEED_ENCODE;
+ return SSL_FULL;
+ }
+ return SSL_ERROR;
+}
+
+/******************************************************************************/
+/*
+ The workhorse for parsing handshake messages. Also enforces the state
+ machine for proper ordering of handshake messages.
+ Parameters:
+ ssl - ssl context
+ inbuf - buffer to read handshake message from
+ len - data length for the current ssl record. The ssl record
+ can contain multiple handshake messages, so we may need to parse
+ them all here.
+ Return:
+ SSL_SUCCESS
+ SSL_PROCESS_DATA
+ SSL_ERROR - see ssl->err for details
+*/
+static int32 parseSSLHandshake(ssl_t *ssl, char *inbuf, int32 len)
+{
+ unsigned char *c;
+ unsigned char *end;
+ unsigned char hsType;
+ int32 i, hsLen, rc, parseLen = 0;
+ uint32 cipher = 0;
+ unsigned char hsMsgHash[SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE];
+
+#ifdef USE_SERVER_SIDE_SSL
+ unsigned char *p;
+ int32 suiteLen, challengeLen, pubKeyLen, extLen;
+#endif /* USE_SERVER_SIDE_SSL */
+
+#ifdef USE_CLIENT_SIDE_SSL
+ int32 sessionIdLen, certMatch, certTypeLen;
+ sslCert_t *subjectCert;
+ int32 valid, certLen, certChainLen, anonCheck;
+ sslCert_t *cert, *currentCert;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ rc = SSL_SUCCESS;
+ c = (unsigned char*)inbuf;
+ end = (unsigned char*)(inbuf + len);
+
+
+parseHandshake:
+ if (end - c < 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid length of handshake message\n", NULL);
+ return SSL_ERROR;
+ }
+ hsType = *c; c++;
+/*
+ hsType is the received handshake type and ssl->hsState is the expected
+ handshake type. If it doesn't match, there are some possible cases
+ that are not errors. These are checked here.
+*/
+ if (hsType != ssl->hsState &&
+ (hsType != SSL_HS_CLIENT_HELLO || ssl->hsState != SSL_HS_DONE)) {
+
+/*
+ A mismatch is possible in the client authentication case.
+ The optional CERTIFICATE_REQUEST may be appearing instead of
+ SERVER_HELLO_DONE.
+*/
+ if ((hsType == SSL_HS_CERTIFICATE_REQUEST) &&
+ (ssl->hsState == SSL_HS_SERVER_HELLO_DONE)) {
+/*
+ This is where the client is first aware of requested client
+ authentication so we set the flag here.
+*/
+ ssl->flags |= SSL_FLAGS_CLIENT_AUTH;
+ ssl->hsState = SSL_HS_CERTIFICATE_REQUEST;
+ goto hsStateDetermined;
+ }
+/*
+ Another possible mismatch allowed is for a HELLO_REQEST message.
+ Indicates a rehandshake initiated from the server.
+*/
+ if ((hsType == SSL_HS_HELLO_REQUEST) &&
+ (ssl->hsState == SSL_HS_DONE) &&
+ !(ssl->flags & SSL_FLAGS_SERVER)) {
+ sslResetContext(ssl);
+ ssl->hsState = hsType;
+ goto hsStateDetermined;
+ }
+
+
+
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixIntDebugMsg("Invalid type of handshake message: %d\n", hsType);
+ return SSL_ERROR;
+ }
+
+hsStateDetermined:
+ if (hsType == SSL_HS_CLIENT_HELLO) {
+ sslInitHSHash(ssl);
+ if (ssl->hsState == SSL_HS_DONE) {
+/*
+ Rehandshake. Server receiving client hello on existing connection
+*/
+ sslResetContext(ssl);
+ ssl->hsState = hsType;
+ }
+ }
+
+/*
+ We need to get a copy of the message hashes to compare to those sent
+ in the finished message (which does not include a hash of itself)
+ before we update the handshake hashes
+*/
+ if (ssl->hsState == SSL_HS_FINISHED) {
+ sslSnapshotHSHash(ssl, hsMsgHash,
+ (ssl->flags & SSL_FLAGS_SERVER) ? 0 : SSL_FLAGS_SERVER);
+ }
+
+/*
+ Process the handshake header and update the ongoing handshake hash
+ SSLv3:
+ 1 byte type
+ 3 bytes length
+ SSLv2:
+ 1 byte type
+*/
+ if (ssl->rec.majVer >= SSL3_MAJ_VER) {
+ if (end - c < 3) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid length of handshake message\n", NULL);
+ return SSL_ERROR;
+ }
+ hsLen = *c << 16; c++;
+ hsLen += *c << 8; c++;
+ hsLen += *c; c++;
+ if (end - c < hsLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid handshake length\n", NULL);
+ return SSL_ERROR;
+ }
+ sslUpdateHSHash(ssl, c - ssl->hshakeHeadLen,
+ hsLen + ssl->hshakeHeadLen);
+
+ } else if (ssl->rec.majVer == SSL2_MAJ_VER) {
+/*
+ Assume that the handshake len is the same as the incoming ssl record
+ length minus 1 byte (type), this is verified in SSL_HS_CLIENT_HELLO
+*/
+ hsLen = len - 1;
+ sslUpdateHSHash(ssl, (unsigned char*)inbuf, len);
+ } else {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixIntDebugMsg("Invalid record version: %d\n", ssl->rec.majVer);
+ return SSL_ERROR;
+ }
+/*
+ Finished with header. Process each type of handshake message.
+*/
+ switch(ssl->hsState) {
+
+#ifdef USE_SERVER_SIDE_SSL
+ case SSL_HS_CLIENT_HELLO:
+/*
+ First two bytes are the highest supported major and minor SSL versions
+ We support only 3.0 (support 3.1 in commercial version)
+*/
+ if (end - c < 2) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid ssl header version length\n", NULL);
+ return SSL_ERROR;
+ }
+ ssl->reqMajVer = *c; c++;
+ ssl->reqMinVer = *c; c++;
+ if (ssl->reqMajVer >= SSL3_MAJ_VER) {
+ ssl->majVer = ssl->reqMajVer;
+ ssl->minVer = SSL3_MIN_VER;
+
+ } else {
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ matrixIntDebugMsg("Unsupported ssl version: %d\n", ssl->reqMajVer);
+ return SSL_ERROR;
+ }
+/*
+ Support SSLv3 and SSLv2 ClientHello messages. Browsers usually send v2
+ messages for compatibility
+*/
+ if (ssl->rec.majVer > SSL2_MAJ_VER) {
+/*
+ Next is a 32 bytes of random data for key generation
+ and a single byte with the session ID length
+*/
+ if (end - c < SSL_HS_RANDOM_SIZE + 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid length of random data\n", NULL);
+ return SSL_ERROR;
+ }
+ memcpy(ssl->sec.clientRandom, c, SSL_HS_RANDOM_SIZE);
+ c += SSL_HS_RANDOM_SIZE;
+ ssl->sessionIdLen = *c; c++;
+/*
+ If a session length was specified, the client is asking to
+ resume a previously established session to speed up the handshake.
+*/
+ if (ssl->sessionIdLen > 0) {
+ if (ssl->sessionIdLen > SSL_MAX_SESSION_ID_SIZE ||
+ end - c < ssl->sessionIdLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ return SSL_ERROR;
+ }
+ memcpy(ssl->sessionId, c, ssl->sessionIdLen);
+ c += ssl->sessionIdLen;
+/*
+ Look up the session id for ssl session resumption. If found, we
+ load the pre-negotiated masterSecret and cipher.
+ A resumed request must meet the following restrictions:
+ The id must be present in the lookup table
+ The requested version must match the original version
+ The cipher suite list must contain the original cipher suite
+*/
+ if (matrixResumeSession(ssl) >= 0) {
+ ssl->flags &= ~SSL_FLAGS_CLIENT_AUTH;
+ ssl->flags |= SSL_FLAGS_RESUMED;
+ } else {
+ memset(ssl->sessionId, 0, SSL_MAX_SESSION_ID_SIZE);
+ ssl->sessionIdLen = 0;
+ }
+ } else {
+/*
+ Always clear the RESUMED flag if no client session id specified
+*/
+ ssl->flags &= ~SSL_FLAGS_RESUMED;
+ }
+/*
+ Next is the two byte cipher suite list length, network byte order.
+ It must not be zero, and must be a multiple of two.
+*/
+ if (end - c < 2) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid cipher suite list length\n", NULL);
+ return SSL_ERROR;
+ }
+ suiteLen = *c << 8; c++;
+ suiteLen += *c; c++;
+ if (suiteLen == 0 || suiteLen & 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixIntDebugMsg("Unable to parse cipher suite list: %d\n",
+ suiteLen);
+ return SSL_ERROR;
+ }
+/*
+ Now is 'suiteLen' bytes of the supported cipher suite list,
+ listed in order of preference. Loop through and find the
+ first cipher suite we support.
+*/
+ if (end - c < suiteLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ return SSL_ERROR;
+ }
+ p = c + suiteLen;
+ while (c < p) {
+ cipher = *c << 8; c++;
+ cipher += *c; c++;
+/*
+ A resumed session can only match the cipher originally
+ negotiated. Otherwise, match the first cipher that we support
+*/
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ sslAssert(ssl->cipher);
+ if (ssl->cipher->id == cipher) {
+ c = p;
+ break;
+ }
+ } else {
+ if ((ssl->cipher = sslGetCipherSpec(cipher)) != NULL) {
+ c = p;
+ break;
+ }
+ }
+ }
+/*
+ If we fell to the default cipher suite, we didn't have
+ any in common with the client, or the client is being bad
+ and requesting the null cipher!
+*/
+ if (ssl->cipher == NULL || ssl->cipher->id != cipher ||
+ cipher == SSL_NULL_WITH_NULL_NULL) {
+ matrixStrDebugMsg("Can't support requested cipher\n", NULL);
+ ssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL);
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ return SSL_ERROR;
+ }
+
+/*
+ Bypass the compression parameters. Only supporting mandatory NULL
+*/
+ if (end - c < 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid compression header length\n", NULL);
+ return SSL_ERROR;
+ }
+ extLen = *c++;
+ if (end - c < extLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid compression header length\n", NULL);
+ return SSL_ERROR;
+ }
+ c += extLen;
+ } else {
+/*
+ Parse a SSLv2 ClientHello message. The same information is
+ conveyed but the order and format is different.
+ First get the cipher suite length, session id length and challenge
+ (client random) length - all two byte values, network byte order.
+*/
+ if (end - c < 6) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Can't parse hello message\n", NULL);
+ return SSL_ERROR;
+ }
+ suiteLen = *c << 8; c++;
+ suiteLen += *c; c++;
+ if (suiteLen == 0 || suiteLen % 3 != 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Can't parse hello message\n", NULL);
+ return SSL_ERROR;
+ }
+ ssl->sessionIdLen = *c << 8; c++;
+ ssl->sessionIdLen += *c; c++;
+/*
+ A resumed session would use a SSLv3 ClientHello, not SSLv2.
+*/
+ if (ssl->sessionIdLen != 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Bad resumption request\n", NULL);
+ return SSL_ERROR;
+ }
+ challengeLen = *c << 8; c++;
+ challengeLen += *c; c++;
+ if (challengeLen < 16 || challengeLen > 32) {
+ matrixStrDebugMsg("Bad challenge length\n", NULL);
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ return SSL_ERROR;
+ }
+/*
+ Validate the three lengths that were just sent to us, don't
+ want any buffer overflows while parsing the remaining data
+*/
+ if (end - c != suiteLen + ssl->sessionIdLen + challengeLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ return SSL_ERROR;
+ }
+/*
+ Parse the cipher suite list similar to the SSLv3 method, except
+ each suite is 3 bytes, instead of two bytes. We define the suite
+ as an integer value, so either method works for lookup.
+ We don't support session resumption from V2 handshakes, so don't
+ need to worry about matching resumed cipher suite.
+*/
+ p = c + suiteLen;
+ while (c < p) {
+ cipher = *c << 16; c++;
+ cipher += *c << 8; c++;
+ cipher += *c; c++;
+ if ((ssl->cipher = sslGetCipherSpec(cipher)) != NULL) {
+ c = p;
+ break;
+ }
+ }
+ if (ssl->cipher == NULL ||
+ ssl->cipher->id == SSL_NULL_WITH_NULL_NULL) {
+ ssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL);
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ matrixStrDebugMsg("Can't support requested cipher\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ We don't allow session IDs for v2 ClientHellos
+*/
+ if (ssl->sessionIdLen > 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("SSLv2 sessions not allowed\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ The client random (between 16 and 32 bytes) fills the least
+ significant bytes in the (always) 32 byte SSLv3 client random field.
+*/
+ memset(ssl->sec.clientRandom, 0x0, SSL_HS_RANDOM_SIZE);
+ memcpy(ssl->sec.clientRandom + (SSL_HS_RANDOM_SIZE - challengeLen),
+ c, challengeLen);
+ c += challengeLen;
+ }
+/*
+ ClientHello should be the only one in the record.
+*/
+ if (c != end) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid final client hello length\n", NULL);
+ return SSL_ERROR;
+ }
+
+
+/*
+ If we're resuming a handshake, then the next handshake message we
+ expect is the finished message. Otherwise we do the full handshake.
+*/
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ ssl->hsState = SSL_HS_FINISHED;
+ } else {
+ ssl->hsState = SSL_HS_CLIENT_KEY_EXCHANGE;
+ }
+/*
+ Now that we've parsed the ClientHello, we need to tell the caller that
+ we have a handshake response to write out.
+ The caller should call sslWrite upon receiving this return code.
+*/
+ rc = SSL_PROCESS_DATA;
+ break;
+
+ case SSL_HS_CLIENT_KEY_EXCHANGE:
+/*
+ RSA: This message contains the premaster secret encrypted with the
+ server's public key (from the Certificate). The premaster
+ secret is 48 bytes of random data, but the message may be longer
+ than that because the 48 bytes are padded before encryption
+ according to PKCS#1v1.5. After encryption, we should have the
+ correct length.
+*/
+ if (end - c < hsLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid ClientKeyExchange length\n", NULL);
+ return SSL_ERROR;
+ }
+ sslActivatePublicCipher(ssl);
+
+ pubKeyLen = hsLen;
+
+
+/*
+ Now have a handshake pool to allocate the premaster storage
+*/
+ ssl->sec.premasterSize = SSL_HS_RSA_PREMASTER_SIZE;
+ ssl->sec.premaster = psMalloc(ssl->hsPool,
+ SSL_HS_RSA_PREMASTER_SIZE);
+
+ if (ssl->decryptPriv(ssl->hsPool, ssl->keys->cert.privKey, c,
+ pubKeyLen, ssl->sec.premaster, ssl->sec.premasterSize)
+ != ssl->sec.premasterSize) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Failed to decrypt premaster\n", NULL);
+ return SSL_ERROR;
+ }
+
+/*
+ The first two bytes of the decrypted message should be the
+ client's requested version number (which may not be the same
+ as the final negotiated version). The other 46 bytes -
+ pure random!
+
+ SECURITY -
+ Some SSL clients (Including Microsoft IE 6.0) incorrectly set
+ the first two bytes to the negotiated version rather than the
+ requested version. This is known in OpenSSL as the
+ SSL_OP_TLS_ROLLBACK_BUG. We allow this to slide only if we
+ don't support TLS, TLS was requested and the negotiated
+ versions match.
+*/
+ if (*ssl->sec.premaster != ssl->reqMajVer) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Incorrect version in ClientKeyExchange\n",
+ NULL);
+ return SSL_ERROR;
+ }
+ if (*(ssl->sec.premaster + 1) != ssl->reqMinVer) {
+ if (ssl->reqMinVer < TLS_MIN_VER ||
+ *(ssl->sec.premaster + 1) != ssl->minVer) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Incorrect version in ClientKeyExchange\n",
+ NULL);
+ return SSL_ERROR;
+ }
+ }
+
+/*
+ Now that we've got the premaster secret, derive the various
+ symmetric keys using it and the client and server random values.
+ Update the cached session (if found) with the masterSecret and
+ negotiated cipher.
+*/
+ sslDeriveKeys(ssl);
+
+ matrixUpdateSession(ssl);
+
+ c += pubKeyLen;
+ ssl->hsState = SSL_HS_FINISHED;
+
+
+ break;
+#endif /* USE_SERVER_SIDE_SSL */
+
+ case SSL_HS_FINISHED:
+/*
+ Before the finished handshake message, we should have seen the
+ CHANGE_CIPHER_SPEC message come through in the record layer, which
+ would have activated the read cipher, and set the READ_SECURE flag.
+ This is the first handshake message that was sent securely.
+*/
+ if (!(ssl->flags & SSL_FLAGS_READ_SECURE)) {
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ matrixStrDebugMsg("Finished before ChangeCipherSpec\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ The contents of the finished message is a 16 byte MD5 hash followed
+ by a 20 byte sha1 hash of all the handshake messages so far, to verify
+ that nothing has been tampered with while we were still insecure.
+ Compare the message to the value we calculated at the beginning of
+ this function.
+*/
+ if (hsLen != SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Finished length\n", NULL);
+ return SSL_ERROR;
+ }
+ if (end - c < hsLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Finished length\n", NULL);
+ return SSL_ERROR;
+ }
+ if (memcmp(c, hsMsgHash, hsLen) != 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid handshake msg hash\n", NULL);
+ return SSL_ERROR;
+ }
+ c += hsLen;
+ ssl->hsState = SSL_HS_DONE;
+/*
+ Now that we've parsed the Finished message, if we're a resumed
+ connection, we're done with handshaking, otherwise, we return
+ SSL_PROCESS_DATA to get our own cipher spec and finished messages
+ sent out by the caller.
+*/
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+ if (!(ssl->flags & SSL_FLAGS_RESUMED)) {
+ rc = SSL_PROCESS_DATA;
+ }
+ } else {
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ rc = SSL_PROCESS_DATA;
+ }
+ }
+#ifdef USE_CLIENT_SIDE_SSL
+/*
+ Free handshake pool, of which the cert is the primary member.
+ There is also an attempt to free the handshake pool during
+ the sending of the finished message to deal with client
+ and server and differing handshake types. Both cases are
+ attempted keep the lifespan of this pool as short as possible.
+ This is the default case for the server side.
+*/
+ if (ssl->sec.cert) {
+ matrixX509FreeCert(ssl->sec.cert);
+ ssl->sec.cert = NULL;
+ }
+#endif /* USE_CLIENT_SIDE */
+ break;
+
+#ifdef USE_CLIENT_SIDE_SSL
+ case SSL_HS_HELLO_REQUEST:
+/*
+ No body message and the only one in record flight
+*/
+ if (end - c != 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid hello request message\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ Intentionally not changing state here to SERVER_HELLO. The
+ encodeResponse case this will fall into needs to distinguish
+ between calling the normal sslEncodeResponse or encodeClientHello.
+ The HELLO_REQUEST state is used to make that determination and the
+ writing of CLIENT_HELLO will properly move the state along itself.
+*/
+ rc = SSL_PROCESS_DATA;
+ break;
+
+ case SSL_HS_SERVER_HELLO:
+/*
+ First two bytes are the negotiated SSL version
+ We support only 3.0 (other options are 2.0 or 3.1)
+*/
+ if (end - c < 2) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid ssl header version length\n", NULL);
+ return SSL_ERROR;
+ }
+ ssl->reqMajVer = *c; c++;
+ ssl->reqMinVer = *c; c++;
+ if (ssl->reqMajVer != ssl->majVer) {
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ matrixIntDebugMsg("Unsupported ssl version: %d\n", ssl->reqMajVer);
+ return SSL_ERROR;
+ }
+
+/*
+ Next is a 32 bytes of random data for key generation
+ and a single byte with the session ID length
+*/
+ if (end - c < SSL_HS_RANDOM_SIZE + 1) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid length of random data\n", NULL);
+ return SSL_ERROR;
+ }
+ memcpy(ssl->sec.serverRandom, c, SSL_HS_RANDOM_SIZE);
+ c += SSL_HS_RANDOM_SIZE;
+ sessionIdLen = *c; c++;
+ if (sessionIdLen > SSL_MAX_SESSION_ID_SIZE ||
+ end - c < sessionIdLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ return SSL_ERROR;
+ }
+/*
+ If a session length was specified, the server has sent us a
+ session Id. We may have requested a specific session, and the
+ server may or may not agree to use that session.
+*/
+ if (sessionIdLen > 0) {
+ if (ssl->sessionIdLen > 0) {
+ if (memcmp(ssl->sessionId, c, sessionIdLen) == 0) {
+ ssl->flags |= SSL_FLAGS_RESUMED;
+ } else {
+ ssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL);
+ memset(ssl->sec.masterSecret, 0x0, SSL_HS_MASTER_SIZE);
+ ssl->sessionIdLen = sessionIdLen;
+ memcpy(ssl->sessionId, c, sessionIdLen);
+ ssl->flags &= ~SSL_FLAGS_RESUMED;
+ }
+ } else {
+ ssl->sessionIdLen = sessionIdLen;
+ memcpy(ssl->sessionId, c, sessionIdLen);
+ }
+ c += sessionIdLen;
+ } else {
+ if (ssl->sessionIdLen > 0) {
+ ssl->cipher = sslGetCipherSpec(SSL_NULL_WITH_NULL_NULL);
+ memset(ssl->sec.masterSecret, 0x0, SSL_HS_MASTER_SIZE);
+ ssl->sessionIdLen = 0;
+ memset(ssl->sessionId, 0x0, SSL_MAX_SESSION_ID_SIZE);
+ ssl->flags &= ~SSL_FLAGS_RESUMED;
+ }
+ }
+/*
+ Next is the two byte cipher suite
+*/
+ if (end - c < 2) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid cipher suite length\n", NULL);
+ return SSL_ERROR;
+ }
+ cipher = *c << 8; c++;
+ cipher += *c; c++;
+
+/*
+ A resumed session can only match the cipher originally
+ negotiated. Otherwise, match the first cipher that we support
+*/
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ sslAssert(ssl->cipher);
+ if (ssl->cipher->id != cipher) {
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ matrixStrDebugMsg("Can't support resumed cipher\n", NULL);
+ return SSL_ERROR;
+ }
+ } else {
+ if ((ssl->cipher = sslGetCipherSpec(cipher)) == NULL) {
+ ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
+ matrixStrDebugMsg("Can't support requested cipher\n", NULL);
+ return SSL_ERROR;
+ }
+ }
+
+
+/*
+ Decode the compression parameters. Always zero.
+ There are no compression schemes defined for SSLv3
+*/
+ if (end - c < 1 || *c != 0) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid compression value\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ At this point, if we're resumed, we have all the required info
+ to derive keys. The next handshake message we expect is
+ the Finished message.
+*/
+ c++;
+
+ if (ssl->flags & SSL_FLAGS_RESUMED) {
+ sslDeriveKeys(ssl);
+ ssl->hsState = SSL_HS_FINISHED;
+ } else {
+ ssl->hsState = SSL_HS_CERTIFICATE;
+ }
+ break;
+
+ case SSL_HS_CERTIFICATE:
+ if (end - c < 3) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Certificate message\n", NULL);
+ return SSL_ERROR;
+ }
+ certChainLen = *c << 16; c++;
+ certChainLen |= *c << 8; c++;
+ certChainLen |= *c; c++;
+ if (certChainLen == 0) {
+ if (ssl->majVer == SSL3_MAJ_VER && ssl->minVer == SSL3_MIN_VER) {
+ ssl->err = SSL_ALERT_NO_CERTIFICATE;
+ } else {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ }
+ matrixStrDebugMsg("No certificate sent to verify\n", NULL);
+ return SSL_ERROR;
+ }
+ if (end - c < 3) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Certificate message\n", NULL);
+ return SSL_ERROR;
+ }
+
+ i = 0;
+ while (certChainLen > 0) {
+ certLen = *c << 16; c++;
+ certLen |= *c << 8; c++;
+ certLen |= *c; c++;
+
+ if (end - c < certLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid certificate length\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ Extract the binary cert message into the cert structure
+*/
+ if ((parseLen = matrixX509ParseCert(ssl->hsPool, c, certLen, &cert)) < 0) {
+ matrixX509FreeCert(cert);
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ matrixStrDebugMsg("Can't parse certificate\n", NULL);
+ return SSL_ERROR;
+ }
+ c += parseLen;
+
+ if (i++ == 0) {
+ ssl->sec.cert = cert;
+ currentCert = ssl->sec.cert;
+ } else {
+ currentCert->next = cert;
+ currentCert = currentCert->next;
+ }
+ certChainLen -= (certLen + 3);
+ }
+/*
+ May have received a chain of certs in the message. Spec says they
+ must be in order so that each subsequent one is the parent of the
+ previous. Confirm this now.
+*/
+ if (matrixX509ValidateCertChain(ssl->hsPool, ssl->sec.cert,
+ &subjectCert, &valid) < 0) {
+
+/*
+ Hack by @lapshov:
+ If there is a user callback, don't fail on validating cert chain
+ User will have every information to make a decision later
+*/
+ if (ssl->sec.validateCert == NULL) {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ matrixStrDebugMsg("Couldn't validate certificate chain\n", NULL);
+ return SSL_ERROR;
+ }
+ }
+/*
+ There may not be a caCert set. The validate implemenation will just
+ take the subject cert and make sure it is a self signed cert.
+*/
+ if (matrixX509ValidateCert(ssl->hsPool, subjectCert,
+ ssl->keys == NULL ? NULL : ssl->keys->caCerts,
+ &subjectCert->valid) < 0) {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ matrixStrDebugMsg("Error validating certificate\n", NULL);
+ return SSL_ERROR;
+ }
+ if (subjectCert->valid < 0) {
+ matrixStrDebugMsg(
+ "Warning: Cert did not pass default validation checks\n", NULL);
+/*
+ If there is no user callback, fail on validation check because there
+ will be no intervention to give it a second look.
+*/
+ if (ssl->sec.validateCert == NULL) {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ return SSL_ERROR;
+ }
+ }
+/*
+ Call the user validation function with the entire cert chain. The user
+ will proabably want to drill down to the last cert to make sure it
+ has been properly validated by a CA on this side.
+
+ Need to return from user validation space with knowledge
+ that this is an ANONYMOUS connection.
+*/
+ if ((anonCheck = matrixX509UserValidator(ssl->hsPool, ssl->sec.cert,
+ ssl->sec.validateCert, ssl->sec.validateCertArg)) < 0) {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ return SSL_ERROR;
+ }
+/*
+ Set the flag that is checked by the matrixSslGetAnonStatus API
+*/
+ if (anonCheck == SSL_ALLOW_ANON_CONNECTION) {
+ ssl->sec.anon = 1;
+ } else {
+ ssl->sec.anon = 0;
+ }
+
+/*
+ Either a client or server could have been processing the cert as part of
+ the authentication process. If server, we move to the client key
+ exchange state.
+*/
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+ ssl->hsState = SSL_HS_CLIENT_KEY_EXCHANGE;
+ } else {
+ ssl->hsState = SSL_HS_SERVER_HELLO_DONE;
+ }
+ break;
+
+ case SSL_HS_SERVER_HELLO_DONE:
+ if (hsLen != 0) {
+ ssl->err = SSL_ALERT_BAD_CERTIFICATE;
+ matrixStrDebugMsg("Can't validate certificate\n", NULL);
+ return SSL_ERROR;
+ }
+ ssl->hsState = SSL_HS_FINISHED;
+ rc = SSL_PROCESS_DATA;
+ break;
+
+ case SSL_HS_CERTIFICATE_REQUEST:
+ if (hsLen < 4) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Certificate Request message\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ We only have RSA_SIGN types. Make sure server can accept them
+*/
+ certMatch = 0;
+ certTypeLen = *c++;
+ if (end - c < certTypeLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Certificate Request message\n", NULL);
+ return SSL_ERROR;
+ }
+ while (certTypeLen-- > 0) {
+ if (*c++ == RSA_SIGN) {
+ certMatch = 1;
+ }
+ }
+ if (certMatch == 0) {
+ ssl->err = SSL_ALERT_UNSUPPORTED_CERTIFICATE;
+ matrixStrDebugMsg("Can only support RSA_SIGN cert authentication\n",
+ NULL);
+ return SSL_ERROR;
+ }
+ certChainLen = *c << 8; c++;
+ certChainLen |= *c; c++;
+ if (end - c < certChainLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid Certificate Request message\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ Check the passed in DNs against our cert issuer to see if they match.
+ Only supporting a single cert on the client side.
+*/
+ ssl->sec.certMatch = 0;
+ while (certChainLen > 0) {
+ certLen = *c << 8; c++;
+ certLen |= *c; c++;
+ if (end - c < certLen) {
+ ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
+ matrixStrDebugMsg("Invalid CertificateRequest message\n", NULL);
+ return SSL_ERROR;
+ }
+ c += certLen;
+ certChainLen -= (2 + certLen);
+ }
+ ssl->hsState = SSL_HS_SERVER_HELLO_DONE;
+ break;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+ case SSL_HS_SERVER_KEY_EXCHANGE:
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ return SSL_ERROR;
+
+ default:
+ ssl->err = SSL_ALERT_UNEXPECTED_MESSAGE;
+ return SSL_ERROR;
+ }
+
+
+/*
+ if we've got more data in the record, the sender has packed
+ multiple handshake messages in one record. Parse the next one.
+*/
+ if (c < end) {
+ goto parseHandshake;
+ }
+ return rc;
+}
+
+/******************************************************************************/
diff --git a/contrib/libs/matrixssl/src/sslEncode.c b/contrib/libs/matrixssl/src/sslEncode.c
new file mode 100644
index 00000000000..00d4fb3ad3b
--- /dev/null
+++ b/contrib/libs/matrixssl/src/sslEncode.c
@@ -0,0 +1,1255 @@
+/*
+ * sslEncode.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * Secure Sockets Layer message encoding
+ */
+/*
+ * 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 "matrixInternal.h"
+
+/******************************************************************************/
+
+static int32 writeCertificate(ssl_t *ssl, sslBuf_t *out, int32 notEmpty);
+static int32 writeChangeCipherSpec(ssl_t *ssl, sslBuf_t *out);
+static int32 writeFinished(ssl_t *ssl, sslBuf_t *out);
+static int32 writeAlert(ssl_t *ssl, unsigned char level,
+ unsigned char description, sslBuf_t *out);
+static int32 writeRecordHeader(ssl_t *ssl, int32 type, int32 hsType, int32 *messageSize,
+ char *padLen, unsigned char **encryptStart,
+ unsigned char **end, unsigned char **c);
+
+static int32 encryptRecord(ssl_t *ssl, int32 type, int32 messageSize, int32 padLen,
+ unsigned char *encryptStart, sslBuf_t *out,
+ unsigned char **c);
+
+#ifdef USE_CLIENT_SIDE_SSL
+static int32 writeClientKeyExchange(ssl_t *ssl, sslBuf_t *out);
+#endif /* USE_CLIENT_SIDE_SSL */
+
+#ifdef USE_SERVER_SIDE_SSL
+static int32 writeServerHello(ssl_t *ssl, sslBuf_t *out);
+static int32 writeServerHelloDone(ssl_t *ssl, sslBuf_t *out);
+#endif /* USE_SERVER_SIDE_SSL */
+
+
+static int32 secureWriteAdditions(ssl_t *ssl, int32 numRecs);
+
+/******************************************************************************/
+/*
+ Encode the incoming data into the out buffer for sending to remote peer.
+
+ FUTURE SECURITY - If sending the first application data record, we could
+ prepend it with a blank SSL record to avoid a timing attack. We're fine
+ for now, because this is an impractical attack and the solution is
+ incompatible with some SSL implementations (including some versions of IE).
+ http://www.openssl.org/~bodo/tls-cbc.txt
+*/
+int32 matrixSslEncode(ssl_t *ssl, const unsigned char *in, int32 inlen, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc;
+/*
+ If we've had a protocol error, don't allow further use of the session
+ Also, don't allow a application data record to be encoded unless the
+ handshake is complete.
+*/
+ if (ssl->flags & SSL_FLAGS_ERROR || ssl->hsState != SSL_HS_DONE ||
+ ssl->flags & SSL_FLAGS_CLOSED) {
+ return SSL_ERROR;
+ }
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize = ssl->recordHeadLen + inlen;
+
+/*
+ Validate size constraint
+*/
+ if (messageSize > SSL_MAX_BUF_SIZE) {
+ return SSL_ERROR;
+ }
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_APPLICATION_DATA, 0,
+ &messageSize, &padLen, &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+
+ memcpy(c, in, inlen);
+ c += inlen;
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_APPLICATION_DATA,
+ messageSize, padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+ out->end = c;
+
+ return (int32)(out->end - out->start);
+}
+
+/******************************************************************************/
+/*
+ We indicate to the caller through return codes in sslDecode when we need
+ to write internal data to the remote host. The caller will call this
+ function to generate a message appropriate to our state.
+*/
+int32 sslEncodeResponse(ssl_t *ssl, sslBuf_t *out)
+{
+ int32 messageSize;
+ int32 rc = SSL_ERROR;
+#ifdef USE_SERVER_SIDE_SSL
+ int32 totalCertLen, i;
+ sslLocalCert_t *cert;
+#endif /* USE_SERVER_SIDE_SSL */
+#ifdef USE_CLIENT_SIDE_SSL
+ int32 ckeSize;
+#endif /* USE_CLIENT_SIDE_SSL */
+
+/*
+ We may be trying to encode an alert response if there is an error marked
+ on the connection.
+*/
+ if (ssl->err != SSL_ALERT_NONE) {
+ rc = writeAlert(ssl, SSL_ALERT_LEVEL_FATAL, ssl->err, out);
+ if (rc == SSL_ERROR) {
+ ssl->flags |= SSL_FLAGS_ERROR;
+ }
+ return rc;
+ }
+
+
+/*
+ We encode a set of response messages based on our current state
+ We have to pre-verify the size of the outgoing buffer against
+ all the messages to make the routine transactional. If the first
+ write succeeds and the second fails because of size, we cannot
+ rollback the state of the cipher and MAC.
+*/
+ switch (ssl->hsState) {
+/*
+ If we're waiting for the ClientKeyExchange message, then we need to
+ send the messages that would prompt that result on the client
+*/
+#ifdef USE_SERVER_SIDE_SSL
+ case SSL_HS_CLIENT_KEY_EXCHANGE:
+
+/*
+ This is the entry point for a server encoding the first flight
+ of a non-DH, non-client-auth handshake.
+*/
+ totalCertLen = 0;
+ cert = &ssl->keys->cert;
+ for (i = 0; cert != NULL; i++) {
+ totalCertLen += cert->certLen;
+ cert = cert->next;
+ }
+ messageSize =
+ 3 * ssl->recordHeadLen +
+ 3 * ssl->hshakeHeadLen +
+ 38 + SSL_MAX_SESSION_ID_SIZE + /* server hello */
+ 3 + (i * 3) + totalCertLen; /* certificate */
+
+
+ messageSize += secureWriteAdditions(ssl, 3);
+
+ if ((out->buf + out->size) - out->end < messageSize) {
+ return SSL_FULL;
+ }
+/*
+ Message size complete. Begin the flight write
+*/
+ rc = writeServerHello(ssl, out);
+
+ if (rc == SSL_SUCCESS) {
+ rc = writeCertificate(ssl, out, 1);
+ }
+
+ if (rc == SSL_SUCCESS) {
+ rc = writeServerHelloDone(ssl, out);
+ }
+ break;
+
+#endif /* USE_SERVER_SIDE_SSL */
+
+/*
+ If we're not waiting for any message from client, then we need to
+ send our finished message
+*/
+ case SSL_HS_DONE:
+ messageSize = 2 * ssl->recordHeadLen +
+ ssl->hshakeHeadLen +
+ 1 + /* change cipher spec */
+ SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE; /* finished */
+/*
+ Account for possible overhead in CCS message with secureWriteAdditions
+ then always account for the encrypted FINISHED message
+*/
+ messageSize += secureWriteAdditions(ssl, 1);
+ messageSize += ssl->enMacSize + /* handshake msg hash */
+ (ssl->cipher->blockSize - 1); /* max padding */
+
+ if ((out->buf + out->size) - out->end < messageSize) {
+ return SSL_FULL;
+ }
+ rc = writeChangeCipherSpec(ssl, out);
+ if (rc == SSL_SUCCESS) {
+ rc = writeFinished(ssl, out);
+ }
+ break;
+/*
+ If we're expecting a Finished message, as a server we're doing
+ session resumption. As a client, we're completing a normal
+ handshake
+*/
+ case SSL_HS_FINISHED:
+#ifdef USE_SERVER_SIDE_SSL
+ if (ssl->flags & SSL_FLAGS_SERVER) {
+ messageSize =
+ 3 * ssl->recordHeadLen +
+ 2 * ssl->hshakeHeadLen +
+ 38 + SSL_MAX_SESSION_ID_SIZE + /* server hello */
+ 1 + /* change cipher spec */
+ SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE; /* finished */
+/*
+ Account for possible overhead with secureWriteAdditions
+ then always account for the encrypted FINISHED message
+*/
+ messageSize += secureWriteAdditions(ssl, 2);
+ messageSize += ssl->enMacSize + /* handshake msg hash */
+ (ssl->cipher->blockSize - 1); /* max padding */
+ if ((out->buf + out->size) - out->end < messageSize) {
+ return SSL_FULL;
+ }
+ rc = writeServerHello(ssl, out);
+ if (rc == SSL_SUCCESS) {
+ rc = writeChangeCipherSpec(ssl, out);
+ }
+ if (rc == SSL_SUCCESS) {
+ rc = writeFinished(ssl, out);
+ }
+ }
+#endif /* USE_SERVER_SIDE_SSL */
+#ifdef USE_CLIENT_SIDE_SSL
+/*
+ Encode entry point for client side final flight encodes.
+ First task here is to find out size of ClientKeyExchange message
+*/
+ if (!(ssl->flags & SSL_FLAGS_SERVER)) {
+ ckeSize = 0;
+/*
+ Normal RSA auth cipher suite case
+*/
+ if (ssl->sec.cert == NULL) {
+ ssl->flags |= SSL_FLAGS_ERROR;
+ return SSL_ERROR;
+ }
+ ckeSize = ssl->sec.cert->publicKey.size;
+
+ messageSize = 0;
+/*
+ Client authentication requires the client to send a CERTIFICATE
+ and CERTIFICATE_VERIFY message. Account for the length. It
+ is possible the client didn't have a match for the requested cert.
+ Send an empty certificate message in that case (or alert for SSLv3)
+*/
+ if (ssl->flags & SSL_FLAGS_CLIENT_AUTH) {
+ if (ssl->sec.certMatch > 0) {
+/*
+ Account for the certificate and certificateVerify messages
+*/
+ messageSize += 6 + (2 * ssl->recordHeadLen) +
+ (2 * ssl->hshakeHeadLen) + ssl->keys->cert.certLen +
+ 2 + ssl->keys->cert.privKey->size;
+ } else {
+/*
+ SSLv3 sends a no_certificate warning alert for no match
+*/
+ if (ssl->majVer == SSL3_MAJ_VER
+ && ssl->minVer == SSL3_MIN_VER) {
+ messageSize += 2 + ssl->recordHeadLen;
+ } else {
+/*
+ TLS just sends an empty certificate message
+*/
+ messageSize += 3 + ssl->recordHeadLen +
+ ssl->hshakeHeadLen;
+ }
+ }
+ }
+/*
+ Account for the header and message size for all records. The
+ finished message will always be encrypted, so account for one
+ largest possible MAC size and block size. Minus one
+ for padding. The finished message is not accounted for in the
+ writeSecureAddition calls below since it is accounted for here.
+*/
+ messageSize +=
+ 3 * ssl->recordHeadLen +
+ 2 * ssl->hshakeHeadLen + /* change cipher has no hsHead */
+ ckeSize + /* client key exchange */
+ 1 + /* change cipher spec */
+ SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE + /* SSLv3 finished */
+ SSL_MAX_MAC_SIZE + SSL_MAX_BLOCK_SIZE - 1;
+ if (ssl->flags & SSL_FLAGS_CLIENT_AUTH) {
+/*
+ Secure write for ClientKeyExchange, ChangeCipherSpec,
+ Certificate, and CertificateVerify. Don't account for
+ Certificate and/or CertificateVerify message if no auth cert.
+ This will also cover the NO_CERTIFICATE alert sent in
+ replacement of the NULL certificate message in SSLv3.
+*/
+ if (ssl->sec.certMatch > 0) {
+ messageSize += secureWriteAdditions(ssl, 4);
+ } else {
+ messageSize += secureWriteAdditions(ssl, 3);
+ }
+ } else {
+ messageSize += secureWriteAdditions(ssl, 2);
+ }
+
+
+/*
+ The actual buffer size test to hold this flight
+*/
+ if ((out->buf + out->size) - out->end < messageSize) {
+ return SSL_FULL;
+ }
+ rc = SSL_SUCCESS;
+
+ if (ssl->flags & SSL_FLAGS_CLIENT_AUTH) {
+ if (ssl->sec.certMatch == 0 && ssl->majVer == SSL3_MAJ_VER
+ && ssl->minVer == SSL3_MIN_VER) {
+ rc = writeAlert(ssl, SSL_ALERT_LEVEL_WARNING,
+ SSL_ALERT_NO_CERTIFICATE, out);
+ } else {
+ rc = writeCertificate(ssl, out, ssl->sec.certMatch);
+ }
+ }
+
+ if (rc == SSL_SUCCESS) {
+ rc = writeClientKeyExchange(ssl, out);
+ }
+ if (rc == SSL_SUCCESS) {
+ rc = writeChangeCipherSpec(ssl, out);
+ }
+ if (rc == SSL_SUCCESS) {
+ rc = writeFinished(ssl, out);
+ }
+ }
+#endif /* USE_CLIENT_SIDE_SSL */
+ break;
+ }
+ if (rc == SSL_ERROR) {
+ ssl->flags |= SSL_FLAGS_ERROR;
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ Message size must account for any additional length a secure-write
+ would add to the message. It would be too late to check length in
+ the writeRecordHeader call since some of the handshake hashing could
+ have already taken place and we can't rewind those hashes.
+*/
+static int32 secureWriteAdditions(ssl_t *ssl, int32 numRecs)
+{
+ int32 add = 0;
+/*
+ There is a slim chance for a false FULL message due to the fact that
+ the maximum padding is being calculated rather than the actual number.
+ Caller must simply grow buffer and try again.
+*/
+ if (ssl->flags & SSL_FLAGS_WRITE_SECURE) {
+ add += (numRecs * ssl->enMacSize) + /* handshake msg hash */
+ (numRecs * (ssl->enBlockSize - 1)); /* max padding */
+ }
+ return add;
+}
+
+/******************************************************************************/
+/*
+ Write out a closure alert message (the only user initiated alert)
+ The user would call this when about to initate a socket close
+*/
+int32 matrixSslEncodeClosureAlert(ssl_t *ssl, sslBuf_t *out)
+{
+/*
+ If we've had a protocol error, don't allow further use of the session
+*/
+ if (ssl->flags & SSL_FLAGS_ERROR) {
+ return SSL_ERROR;
+ }
+ return writeAlert(ssl, SSL_ALERT_LEVEL_WARNING, SSL_ALERT_CLOSE_NOTIFY,
+ out);
+}
+
+/******************************************************************************/
+/*
+ Generic record header construction for alerts, handshake messages, and
+ change cipher spec. Determines message length for encryption and
+ writes out to buffer up to the real message data.
+*/
+static int32 writeRecordHeader(ssl_t *ssl, int32 type, int32 hsType,
+ int32 *messageSize, char *padLen, unsigned char **encryptStart,
+ unsigned char **end, unsigned char **c)
+{
+ int32 messageData, msn;
+
+ messageData = *messageSize - ssl->recordHeadLen;
+ if (type == SSL_RECORD_TYPE_HANDSHAKE) {
+ messageData -= ssl->hshakeHeadLen;
+ }
+
+
+/*
+ If this session is already in a secure-write state, determine padding
+*/
+ *padLen = 0;
+ if (ssl->flags & SSL_FLAGS_WRITE_SECURE) {
+ *messageSize += ssl->enMacSize;
+ *padLen = sslPadLenPwr2(*messageSize - ssl->recordHeadLen,
+ ssl->enBlockSize);
+ *messageSize += *padLen;
+ }
+
+ if (*end - *c < *messageSize) {
+/*
+ Callers other than sslEncodeResponse do not necessarily check for
+ FULL before calling. We do it here for them.
+*/
+ return SSL_FULL;
+ }
+
+
+ *c += psWriteRecordInfo(ssl, type, *messageSize - ssl->recordHeadLen, *c);
+
+/*
+ All data written after this point is to be encrypted (if secure-write)
+*/
+ *encryptStart = *c;
+ msn = 0;
+
+
+/*
+ Handshake records have another header layer to write here
+*/
+ if (type == SSL_RECORD_TYPE_HANDSHAKE) {
+ *c += psWriteHandshakeHeader(ssl, hsType, messageData, msn, 0,
+ messageData, *c);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ Encrypt the message using the current cipher. This call is used in
+ conjunction with the writeRecordHeader function above to finish writing
+ an SSL record. Updates handshake hash if necessary, generates message
+ MAC, writes the padding, and does the encrytion.
+*/
+static int32 encryptRecord(ssl_t *ssl, int32 type, int32 messageSize,
+ int32 padLen, unsigned char *encryptStart,
+ sslBuf_t *out, unsigned char **c)
+{
+ if (type == SSL_RECORD_TYPE_HANDSHAKE) {
+ sslUpdateHSHash(ssl, encryptStart, (int32)(*c - encryptStart));
+ }
+ *c += ssl->generateMac(ssl, type, encryptStart,
+ (int32)(*c - encryptStart), *c);
+
+ *c += sslWritePad(*c, padLen);
+
+ if (ssl->encrypt(&ssl->sec.encryptCtx, encryptStart, encryptStart,
+ (int32)(*c - encryptStart)) < 0 || *c - out->end != messageSize) {
+ matrixStrDebugMsg("Error encrypting message for write\n", NULL);
+ return SSL_ERROR;
+ }
+
+ return 0;
+}
+
+#ifdef USE_SERVER_SIDE_SSL
+/******************************************************************************/
+/*
+ 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;
+}
+
+/******************************************************************************/
+/*
+ ServerHelloDone message is a blank handshake message
+*/
+static int32 writeServerHelloDone(ssl_t *ssl, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc;
+
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize =
+ ssl->recordHeadLen +
+ ssl->hshakeHeadLen;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE,
+ SSL_HS_SERVER_HELLO_DONE, &messageSize, &padLen,
+ &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Error generating hello done for write\n", NULL);
+ return SSL_ERROR;
+ }
+ out->end = c;
+ return SSL_SUCCESS;
+}
+
+
+/******************************************************************************/
+/*
+ Server initiated rehandshake public API call.
+*/
+int32 matrixSslEncodeHelloRequest(ssl_t *ssl, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc;
+
+ if (ssl->flags & SSL_FLAGS_ERROR || ssl->flags & SSL_FLAGS_CLOSED) {
+ return SSL_ERROR;
+ }
+ if (!(ssl->flags & SSL_FLAGS_SERVER) || (ssl->hsState != SSL_HS_DONE)) {
+ return SSL_ERROR;
+ }
+
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize =
+ ssl->recordHeadLen +
+ ssl->hshakeHeadLen;
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE,
+ SSL_HS_HELLO_REQUEST, &messageSize, &padLen,
+ &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Error generating hello request for write\n", NULL);
+ return SSL_ERROR;
+ }
+ out->end = c;
+
+ return SSL_SUCCESS;
+}
+#else /* USE_SERVER_SIDE_SSL */
+int32 matrixSslEncodeHelloRequest(ssl_t *ssl, sslBuf_t *out)
+{
+ matrixStrDebugMsg("Library not built with USE_SERVER_SIDE_SSL\n", NULL);
+ return -1;
+}
+#endif /* USE_SERVER_SIDE_SSL */
+
+/******************************************************************************/
+/*
+ Write a Certificate message.
+ The encoding of the message is as follows:
+ 3 byte length of certificate data (network byte order)
+ If there is no certificate,
+ 3 bytes of 0
+ If there is one certificate,
+ 3 byte length of certificate + 3
+ 3 byte length of certificate
+ certificate data
+ For more than one certificate:
+ 3 byte length of all certificate data
+ 3 byte length of first certificate
+ first certificate data
+ 3 byte length of second certificate
+ second certificate data
+ Certificate data is the base64 section of an X.509 certificate file
+ in PEM format decoded to binary. No additional interpretation is required.
+*/
+static int32 writeCertificate(ssl_t *ssl, sslBuf_t *out, int32 notEmpty)
+{
+ sslLocalCert_t *cert;
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 totalCertLen, certLen, lsize, messageSize, i, rc;
+
+
+ c = out->end;
+ end = out->buf + out->size;
+
+/*
+ Determine total length of certs
+*/
+ totalCertLen = i = 0;
+ if (notEmpty) {
+ cert = &ssl->keys->cert;
+ for (; cert != NULL; i++) {
+ totalCertLen += cert->certLen;
+ cert = cert->next;
+ }
+ }
+/*
+ Account for the 3 bytes of certChain len for each cert and get messageSize
+*/
+ lsize = 3 + (i * 3);
+ messageSize =
+ ssl->recordHeadLen +
+ ssl->hshakeHeadLen +
+ lsize + totalCertLen;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE,
+ SSL_HS_CERTIFICATE, &messageSize, &padLen, &encryptStart,
+ &end, &c)) < 0) {
+ return rc;
+ }
+
+/*
+ Write out the certs
+*/
+ *c = ((totalCertLen + (lsize - 3)) & 0xFF0000) >> 16; c++;
+ *c = ((totalCertLen + (lsize - 3)) & 0xFF00) >> 8; c++;
+ *c = ((totalCertLen + (lsize - 3)) & 0xFF); c++;
+
+ if (notEmpty) {
+ cert = &ssl->keys->cert;
+ while (cert) {
+ certLen = cert->certLen;
+ if (certLen > 0) {
+ *c = (certLen & 0xFF0000) >> 16; c++;
+ *c = (certLen & 0xFF00) >> 8; c++;
+ *c = (certLen & 0xFF); c++;
+ memcpy(c, cert->certBin, certLen);
+ c += certLen;
+ }
+ cert = cert->next;
+ }
+ }
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Error parsing certificate for write\n", NULL);
+ return SSL_ERROR;
+ }
+ out->end = c;
+ return SSL_SUCCESS;
+}
+
+/******************************************************************************/
+/*
+ Write the ChangeCipherSpec message. It has its own message type
+ and contains just one byte of value one. It is not a handshake
+ message, so it isn't included in the handshake hash.
+*/
+static int32 writeChangeCipherSpec(ssl_t *ssl, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc;
+
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize = ssl->recordHeadLen + 1;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC, 0,
+ &messageSize, &padLen, &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+ *c = 1; c++;
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_CHANGE_CIPHER_SPEC,
+ messageSize, padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Error generating change cipher for write\n", NULL);
+ return SSL_ERROR;
+ }
+ out->end = c;
+/*
+ After the peer parses the ChangeCipherSpec message, it will expect
+ the next message to be encrypted, so activate encryption on outgoing
+ data now
+*/
+ sslActivateWriteCipher(ssl);
+
+
+ return SSL_SUCCESS;
+}
+
+/******************************************************************************/
+/*
+ Write the Finished message
+ The message contains the 36 bytes, the 16 byte MD5 and 20 byte SHA1 hash
+ of all the handshake messages so far (excluding this one!)
+*/
+static int32 writeFinished(ssl_t *ssl, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, verifyLen, rc;
+
+ c = out->end;
+ end = out->buf + out->size;
+ verifyLen = SSL_MD5_HASH_SIZE + SSL_SHA1_HASH_SIZE;
+ messageSize = ssl->recordHeadLen + ssl->hshakeHeadLen + verifyLen;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE, SSL_HS_FINISHED,
+ &messageSize, &padLen, &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+/*
+ Output the hash of messages we've been collecting so far into the buffer
+*/
+ c += sslSnapshotHSHash(ssl, c, ssl->flags & SSL_FLAGS_SERVER);
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Error generating finished for write\n", NULL);
+ return SSL_ERROR;
+ }
+ out->end = c;
+
+
+#ifdef USE_CLIENT_SIDE_SSL
+/*
+ Free handshake pool, of which the cert is the primary member.
+ There is also an attempt to free the handshake pool during
+ the reciept of the finished message. Both cases are attempted
+ to keep the lifespan of this pool as short as possible. This
+ is the default case for the client side.
+*/
+ if (ssl->sec.cert) {
+ matrixX509FreeCert(ssl->sec.cert);
+ ssl->sec.cert = NULL;
+ }
+#endif /* USE_CLIENT_SIDE */
+
+
+ return SSL_SUCCESS;
+}
+
+/******************************************************************************/
+/*
+ Write an Alert message
+ The message contains two bytes: AlertLevel and AlertDescription
+*/
+static int32 writeAlert(ssl_t *ssl, unsigned char level,
+ unsigned char description, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc;
+
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize = 2 + ssl->recordHeadLen;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_ALERT, 0, &messageSize,
+ &padLen, &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+ *c = level; c++;
+ *c = description; c++;
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_ALERT, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ out->end = c;
+ return SSL_SUCCESS;
+}
+
+#ifdef USE_CLIENT_SIDE_SSL
+/******************************************************************************/
+/*
+ Write out the ClientHello message to a buffer
+*/
+int32 matrixSslEncodeClientHello(ssl_t *ssl, sslBuf_t *out,
+ unsigned short cipherSpec)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, rc, cipherLen, cookieLen;
+ time_t t;
+
+ if (ssl->flags & SSL_FLAGS_ERROR || ssl->flags & SSL_FLAGS_CLOSED) {
+ return SSL_ERROR;
+ }
+ if (ssl->flags & SSL_FLAGS_SERVER || (ssl->hsState != SSL_HS_SERVER_HELLO &&
+ ssl->hsState != SSL_HS_DONE &&
+ ssl->hsState != SSL_HS_HELLO_REQUEST )) {
+ return SSL_ERROR;
+ }
+
+ sslInitHSHash(ssl);
+
+ cookieLen = 0;
+/*
+ If session resumption is being done on a rehandshake, make sure we are
+ sending the same cipher spec as the currently negotiated one. If no
+ resumption, clear the RESUMED flag in case the caller forgot to clear
+ it with matrixSslSetSessionOption.
+*/
+ if (ssl->sessionIdLen > 0) {
+ cipherSpec = ssl->cipher->id;
+ } else {
+ ssl->flags &= ~SSL_FLAGS_RESUMED;
+ }
+
+/*
+ If a cipher is specified it is two bytes length and two bytes data.
+*/
+ if (cipherSpec == 0) {
+ cipherLen = sslGetCipherSpecListLen();
+ } else {
+ if (sslGetCipherSpec(cipherSpec) == NULL) {
+ matrixIntDebugMsg("Cipher suite not supported: %d\n", cipherSpec);
+ return SSL_ERROR;
+ }
+ cipherLen = 4;
+ }
+
+ c = out->end;
+ end = out->buf + out->size;
+/*
+ Calculate the size of the message up front, and write header
+*/
+ messageSize = ssl->recordHeadLen + ssl->hshakeHeadLen +
+ 5 + SSL_HS_RANDOM_SIZE + ssl->sessionIdLen + cipherLen + cookieLen;
+
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE,
+ SSL_HS_CLIENT_HELLO, &messageSize, &padLen, &encryptStart,
+ &end, &c)) < 0) {
+ return rc;
+ }
+
+/*
+ First 4 bytes of the serverRandom are the unix time to prevent replay
+ attacks, the rest are random
+*/
+
+ t = time(0);
+ ssl->sec.clientRandom[0] = (unsigned char)((t & 0xFF000000) >> 24);
+ ssl->sec.clientRandom[1] = (unsigned char)((t & 0xFF0000) >> 16);
+ ssl->sec.clientRandom[2] = (unsigned char)((t & 0xFF00) >> 8);
+ ssl->sec.clientRandom[3] = (unsigned char)(t & 0xFF);
+ if (sslGetEntropy(ssl->sec.clientRandom + 4, SSL_HS_RANDOM_SIZE - 4) < 0) {
+ matrixStrDebugMsg("Error gathering clientRandom entropy\n", NULL);
+ return SSL_ERROR;
+ }
+/*
+ First two fields in the ClientHello message are the maximum major
+ and minor SSL protocol versions we support
+*/
+ *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.clientRandom, 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.
+ If we are asking to resume a session, then the sessionId would have
+ been set at session creation time.
+*/
+ *c = ssl->sessionIdLen; c++;
+ if (ssl->sessionIdLen > 0) {
+ memcpy(c, ssl->sessionId, ssl->sessionIdLen);
+ c += ssl->sessionIdLen;
+ }
+/*
+ Write out the length and ciphers we support
+ Client can request a single specific cipher in the cipherSpec param
+*/
+ if (cipherSpec == 0) {
+ if ((rc = sslGetCipherSpecList(c, (int32)(end - c))) < 0) {
+ return SSL_FULL;
+ }
+ c += rc;
+ } else {
+ if ((int32)(end - c) < 4) {
+ return SSL_FULL;
+ }
+ *c = 0; c++;
+ *c = 2; c++;
+ *c = (cipherSpec & 0xFF00) >> 8; c++;
+ *c = cipherSpec & 0xFF; c++;
+ }
+/*
+ Followed by two bytes (len and compression method (always zero))
+*/
+ *c = 1; c++;
+ *c = 0; c++;
+
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+/*
+ 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;
+
+/*
+ Could be a rehandshake so clean up old context if necessary.
+ Always explicitly set state to beginning.
+*/
+ if (ssl->hsState == SSL_HS_DONE) {
+ sslResetContext(ssl);
+ }
+
+/*
+ Could be a rehandshake on a previous connection that used client auth.
+ Reset our local client auth state as the server is always the one
+ responsible for initiating it.
+*/
+ ssl->flags &= ~SSL_FLAGS_CLIENT_AUTH;
+ ssl->hsState = SSL_HS_SERVER_HELLO;
+ return SSL_SUCCESS;
+}
+
+/******************************************************************************/
+/*
+ Write a ClientKeyExchange message.
+*/
+static int32 writeClientKeyExchange(ssl_t *ssl, sslBuf_t *out)
+{
+ unsigned char *c, *end, *encryptStart;
+ char padLen;
+ int32 messageSize, keyLen, explicitLen, rc;
+
+ c = out->end;
+ end = out->buf + out->size;
+ messageSize = keyLen = 0;
+
+
+
+/*
+ Determine messageSize for the record header
+*/
+ /* Standard RSA auth suites */
+ keyLen = ssl->sec.cert->publicKey.size;
+
+ messageSize += ssl->recordHeadLen + ssl->hshakeHeadLen + keyLen;
+ explicitLen = 0;
+
+ if ((rc = writeRecordHeader(ssl, SSL_RECORD_TYPE_HANDSHAKE,
+ SSL_HS_CLIENT_KEY_EXCHANGE, &messageSize, &padLen,
+ &encryptStart, &end, &c)) < 0) {
+ return rc;
+ }
+
+/*
+ ClientKeyExchange message contains the encrypted premaster secret.
+ The base premaster is the original SSL protocol version we asked for
+ followed by 46 bytes of random data.
+ These 48 bytes are padded to the current RSA key length and encrypted
+ with the RSA key.
+*/
+ if (explicitLen == 1) {
+
+/*
+ Add the two bytes of key length
+*/
+ if (keyLen > 0) {
+ *c = (keyLen & 0xFF00) >> 8; c++;
+ *c = (keyLen & 0xFF); c++;
+ }
+ }
+
+
+/*
+ Standard RSA suite
+*/
+ ssl->sec.premasterSize = SSL_HS_RSA_PREMASTER_SIZE;
+ ssl->sec.premaster = psMalloc(ssl->hsPool,
+ SSL_HS_RSA_PREMASTER_SIZE);
+
+ ssl->sec.premaster[0] = ssl->reqMajVer;
+ ssl->sec.premaster[1] = ssl->reqMinVer;
+ if (sslGetEntropy(ssl->sec.premaster + 2,
+ SSL_HS_RSA_PREMASTER_SIZE - 2) < 0) {
+ matrixStrDebugMsg("Error gathering premaster entropy\n", NULL);
+ return SSL_ERROR;
+ }
+
+ sslActivatePublicCipher(ssl);
+
+ if (ssl->encryptPub(ssl->hsPool, &(ssl->sec.cert->publicKey),
+ ssl->sec.premaster, ssl->sec.premasterSize, c,
+ (int32)(end - c)) != keyLen) {
+ matrixStrDebugMsg("Error encrypting premaster\n", NULL);
+ return SSL_FULL;
+ }
+
+ c += keyLen;
+
+ if ((rc = encryptRecord(ssl, SSL_RECORD_TYPE_HANDSHAKE, messageSize,
+ padLen, encryptStart, out, &c)) < 0) {
+ return rc;
+ }
+
+ if (c - out->end != messageSize) {
+ matrixStrDebugMsg("Invalid ClientKeyExchange length\n", NULL);
+ return SSL_ERROR;
+ }
+
+/*
+ Now that we've got the premaster secret, derive the various symmetric
+ keys using it and the client and server random values
+*/
+ sslDeriveKeys(ssl);
+
+ out->end = c;
+ return SSL_SUCCESS;
+}
+
+
+#else /* USE_CLIENT_SIDE_SSL */
+/******************************************************************************/
+/*
+ Stub out this function rather than ifdef it out in the public header
+*/
+int32 matrixSslEncodeClientHello(ssl_t *ssl, sslBuf_t *out,
+ unsigned short cipherSpec)
+{
+ matrixStrDebugMsg("Library not built with USE_CLIENT_SIDE_SSL\n", NULL);
+ return -1;
+}
+#endif /* USE_CLIENT_SIDE_SSL */
+
+
+/******************************************************************************/
+/*
+ Write out a SSLv3 record header.
+ Assumes 'c' points to a buffer of at least SSL3_HEADER_LEN bytes
+ 1 byte type (SSL_RECORD_TYPE_*)
+ 1 byte major version
+ 1 byte minor version
+ 2 bytes length (network byte order)
+ Returns the number of bytes written
+*/
+int32 psWriteRecordInfo(ssl_t *ssl, unsigned char type, int32 len, unsigned char *c)
+{
+ *c = type; c++;
+ *c = ssl->majVer; c++;
+ *c = ssl->minVer; c++;
+ *c = (len & 0xFF00) >> 8; c++;
+ *c = (len & 0xFF);
+
+ return ssl->recordHeadLen;
+}
+
+/******************************************************************************/
+/*
+ Write out an ssl handshake message header.
+ Assumes 'c' points to a buffer of at least ssl->hshakeHeadLen bytes
+ 1 byte type (SSL_HS_*)
+ 3 bytes length (network byte order)
+ Returns the number of bytes written
+*/
+int32 psWriteHandshakeHeader(ssl_t *ssl, unsigned char type, int32 len,
+ int32 seq, int32 fragOffset, int32 fragLen,
+ unsigned char *c)
+{
+ *c = type; c++;
+ *c = (len & 0xFF0000) >> 16; c++;
+ *c = (len & 0xFF00) >> 8; c++;
+ *c = (len & 0xFF);
+
+ return ssl->hshakeHeadLen;
+}
+
+/******************************************************************************/
+/*
+ Write pad bytes and pad length per the TLS spec. Most block cipher
+ padding fills each byte with the number of padding bytes, but SSL/TLS
+ pretends one of these bytes is a pad length, and the remaining bytes are
+ filled with that length. The end result is that the padding is identical
+ to standard padding except the values are one less. For SSLv3 we are not
+ required to have any specific pad values, but they don't hurt.
+
+ PadLen Result
+ 0
+ 1 00
+ 2 01 01
+ 3 02 02 02
+ 4 03 03 03 03
+ 5 04 04 04 04 04
+ 6 05 05 05 05 05 05
+ 7 06 06 06 06 06 06 06
+ 8 07 07 07 07 07 07 07 07
+
+ We calculate the length of padding required for a record using
+ sslPadLenPwr2()
+*/
+int32 sslWritePad(unsigned char *p, unsigned char padLen)
+{
+ unsigned char c = padLen;
+
+ while (c-- > 0) {
+ *p++ = padLen - 1;
+ }
+ return padLen;
+}
+
+/******************************************************************************/
+
+
+
diff --git a/contrib/libs/matrixssl/src/sslv3.c b/contrib/libs/matrixssl/src/sslv3.c
new file mode 100644
index 00000000000..86f20a4aa59
--- /dev/null
+++ b/contrib/libs/matrixssl/src/sslv3.c
@@ -0,0 +1,375 @@
+/*
+ * sslv3.c
+ * Release $Name: MATRIXSSL_1_8_7_OPEN $
+ *
+ * SSLv3.0 specific code per http://wp.netscape.com/eng/ssl3.
+ * Primarily dealing with secret generation, message authentication codes
+ * and handshake hashing.
+ */
+/*
+ * 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 "matrixInternal.h"
+
+/******************************************************************************/
+/*
+ Constants used for key generation
+*/
+static const unsigned char SENDER_CLIENT[5] = "CLNT"; /* 0x434C4E54 */
+static const unsigned char SENDER_SERVER[5] = "SRVR"; /* 0x53525652 */
+
+static const unsigned char pad1[48]={
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36
+};
+
+static const unsigned char pad2[48]={
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
+ 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c
+};
+
+static const unsigned char *salt[10]={
+ (const unsigned char *)"A",
+ (const unsigned char *)"BB",
+ (const unsigned char *)"CCC",
+ (const unsigned char *)"DDDD",
+ (const unsigned char *)"EEEEE",
+ (const unsigned char *)"FFFFFF",
+ (const unsigned char *)"GGGGGGG",
+ (const unsigned char *)"HHHHHHHH",
+ (const unsigned char *)"IIIIIIIII",
+ (const unsigned char *)"JJJJJJJJJJ"
+};
+
+/******************************************************************************/
+
+static int32 createKeyBlock(ssl_t *ssl, unsigned char *clientRandom,
+ unsigned char *serverRandom,
+ unsigned char *masterSecret, int32 secretLen);
+
+/******************************************************************************/
+/*
+ * 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;
+}
+
+/******************************************************************************/
+/*
+ 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;
+}
+
+/******************************************************************************/
+/*
+ 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;
+}
+
+#ifdef USE_SHA1_MAC
+/******************************************************************************/
+/*
+ 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;
+}
+#endif /* USE_SHA1_MAC */
+
+#ifdef USE_MD5_MAC
+/******************************************************************************/
+/*
+ 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;
+}
+
+#endif /* USE_MD5_MAC */
+
+/******************************************************************************/
+
+
diff --git a/contrib/libs/matrixssl/src/yandex.c b/contrib/libs/matrixssl/src/yandex.c
new file mode 100644
index 00000000000..352cc4f93a3
--- /dev/null
+++ b/contrib/libs/matrixssl/src/yandex.c
@@ -0,0 +1,9 @@
+/* Made in Yandex */
+
+#include "matrixInternal.h"
+
+void matrixSslClearByteCount(ssl_t *ctx) {
+#ifdef USE_ARC4
+ ctx->sec.decryptCtx.arc4.byteCount = 0;
+#endif
+}