diff options
Diffstat (limited to 'release/src/router/matrixssl/src/pki')
-rw-r--r-- | release/src/router/matrixssl/src/pki/asn1.c | 454 | ||||
-rw-r--r-- | release/src/router/matrixssl/src/pki/matrixPki.h | 138 | ||||
-rw-r--r-- | release/src/router/matrixssl/src/pki/pkiInternal.h | 240 | ||||
-rw-r--r-- | release/src/router/matrixssl/src/pki/rsaPki.c | 682 | ||||
-rw-r--r-- | release/src/router/matrixssl/src/pki/x509.c | 1699 |
5 files changed, 0 insertions, 3213 deletions
diff --git a/release/src/router/matrixssl/src/pki/asn1.c b/release/src/router/matrixssl/src/pki/asn1.c deleted file mode 100644 index 253e910b..00000000 --- a/release/src/router/matrixssl/src/pki/asn1.c +++ /dev/null @@ -1,454 +0,0 @@ -/* - * asn1.c - * Release $Name: MATRIXSSL_1_8_8_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/release/src/router/matrixssl/src/pki/matrixPki.h b/release/src/router/matrixssl/src/pki/matrixPki.h deleted file mode 100644 index aea0f1d5..00000000 --- a/release/src/router/matrixssl/src/pki/matrixPki.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * matrixPki.h - * Release $Name: MATRIXSSL_1_8_8_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 16 -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/release/src/router/matrixssl/src/pki/pkiInternal.h b/release/src/router/matrixssl/src/pki/pkiInternal.h deleted file mode 100644 index ef89feb3..00000000 --- a/release/src/router/matrixssl/src/pki/pkiInternal.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * pkiInternal.h - * Release $Name: MATRIXSSL_1_8_8_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/release/src/router/matrixssl/src/pki/rsaPki.c b/release/src/router/matrixssl/src/pki/rsaPki.c deleted file mode 100644 index 29a40b02..00000000 --- a/release/src/router/matrixssl/src/pki/rsaPki.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * rsaPki.c - * Release $Name: MATRIXSSL_1_8_8_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 - */ - -#ifdef VXWORKS -#include <vxWorks.h> -#endif /* VXWORKS */ - -#include "pkiInternal.h" - -#ifndef WINCE -#ifdef USE_FILE_SYSTEM - #include <sys/stat.h> - #include <signal.h> -#endif /* USE_FILE_SYSTEM */ -#endif /* WINCE */ -/* - 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) { - if (getSet(&p, (int32)(dnEnd - p), &setlen) < 0) { - return -1; - } - if (getSequence(&p, (int32)(dnEnd - p), &llen) < 0) { - return -1; - } - if (dnEnd <= p || (*(p++) != ASN_OID) || - asnParseLength(&p, (int32)(dnEnd - p), &arcLen) < 0 || - (dnEnd - p) < arcLen) { - return -1; - } -/* - id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} - id-at-commonName OBJECT IDENTIFIER ::= {id-at 3} - id-at-countryName OBJECT IDENTIFIER ::= {id-at 6} - id-at-localityName OBJECT IDENTIFIER ::= {id-at 7} - id-at-stateOrProvinceName OBJECT IDENTIFIER ::= {id-at 8} - id-at-organizationName OBJECT IDENTIFIER ::= {id-at 10} - id-at-organizationalUnitName OBJECT IDENTIFIER ::= {id-at 11} -*/ - *pp = p; -/* - FUTURE: Currently skipping OIDs not of type {joint-iso-ccitt(2) ds(5) 4} - However, we could be dealing with an OID we MUST support per RFC. - domainComponent is one such example. -*/ - if (dnEnd - p < 2) { - return -1; - } - if ((*p++ != 85) || (*p++ != 4) ) { - p = *pp; -/* - Move past the OID and string type, get data size, and skip it. - NOTE: Have had problems parsing older certs in this area. -*/ - if (dnEnd - p < arcLen + 1) { - return -1; - } - p += arcLen + 1; - if (asnParseLength(&p, (int32)(dnEnd - p), &llen) < 0 || - dnEnd - p < llen) { - return -1; - } - p = p + llen; - continue; - } -/* - Next are the id of the attribute type and the ASN string type -*/ - if (arcLen != 3 || dnEnd - p < 2) { - return -1; - } - id = (int32)*p++; -/* - Done with OID parsing -*/ - stringType = (int32)*p++; - - 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 (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); - } - } - 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/release/src/router/matrixssl/src/pki/x509.c b/release/src/router/matrixssl/src/pki/x509.c deleted file mode 100644 index fdd3e678..00000000 --- a/release/src/router/matrixssl/src/pki/x509.c +++ /dev/null @@ -1,1699 +0,0 @@ -/* - * x509.c - * Release $Name: MATRIXSSL_1_8_8_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, ¤tCA) < 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)); - - /* note: on error & no CA, flag as invalid, but don't exit as error here (<1.8.7? behavior) -- zzz */ - if (matrixRsaDecryptPub(pool, &(ic->publicKey), - subjectCert->signature, subjectCert->signatureLen, sigOut, - sigLen) < 0) { - matrixStrDebugMsg("Unable to RSA decrypt signature\n", NULL); - if (issuerCert) return -1; - rc = -1; - } else { - 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 */ - - -/******************************************************************************/ - - |