summaryrefslogtreecommitdiff
path: root/release/src/router/matrixssl/src/pki/x509.c
diff options
context:
space:
mode:
Diffstat (limited to 'release/src/router/matrixssl/src/pki/x509.c')
-rw-r--r--release/src/router/matrixssl/src/pki/x509.c1699
1 files changed, 0 insertions, 1699 deletions
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, &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));
-
- /* 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 */
-
-
-/******************************************************************************/
-
-