Tomato 1.27
[tomato.git] / release / src / router / matrixssl / src / pki / x509.c
blobfdd3e678661fd637869bdae3fe25178261d1651b
1 /*
2 * x509.c
3 * Release $Name: MATRIXSSL_1_8_8_OPEN $
5 * DER/BER coding
6 */
7 /*
8 * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
9 * The latest version of this code is available at http://www.matrixssl.org
11 * This software is open source; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This General Public License does NOT permit incorporating this software
17 * into proprietary programs. If you are unable to comply with the GPL, a
18 * commercial license for this software may be purchased from PeerSec Networks
19 * at http://www.peersec.com
21 * This program is distributed in WITHOUT ANY WARRANTY; without even the
22 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 * See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 * http://www.gnu.org/copyleft/gpl.html
30 /******************************************************************************/
32 #include "pkiInternal.h"
35 X509 is wrapped in USE_RSA until more key types are added
37 #ifdef USE_RSA
38 #ifdef USE_X509
40 #define IMPLICIT_ISSUER_ID 1
41 #define IMPLICIT_SUBJECT_ID 2
42 #define EXPLICIT_EXTENSION 3
44 #define RSA_SIG 1
45 #define DSA_SIG 2
47 #define OID_SHA1 88
48 #define OID_MD2 646
49 #define OID_MD5 649
52 Certificate extension hash mappings
54 #define EXT_BASIC_CONSTRAINTS 1
55 #define EXT_KEY_USAGE 2
56 #define EXT_SUBJ_KEY_ID 3
57 #define EXT_AUTH_KEY_ID 4
58 #define EXT_ALT_SUBJECT_NAME 5
60 static const struct {
61 unsigned char hash[16];
62 int32 id;
63 } extTable[] = {
64 { { 0xa5, 0xc4, 0x5e, 0x9a, 0xa3, 0xbb, 0x71, 0x2f, 0x07,
65 0xf7, 0x4c, 0xd0, 0xcd, 0x95, 0x65, 0xda }, EXT_BASIC_CONSTRAINTS },
66 { { 0xf5, 0xab, 0x88, 0x49, 0xc4, 0xfd, 0xa2, 0x64, 0x6d,
67 0x06, 0xa2, 0x3e, 0x83, 0x9b, 0xef, 0xbb }, EXT_KEY_USAGE },
68 { { 0x91, 0x54, 0x28, 0xcc, 0x81, 0x59, 0x8c, 0x71, 0x8c,
69 0x53, 0xa8, 0x4d, 0xeb, 0xd3, 0xc2, 0x18 }, EXT_SUBJ_KEY_ID },
70 { { 0x48, 0x2d, 0xff, 0x49, 0xf7, 0xab, 0x93, 0xe8, 0x1f,
71 0x57, 0xb5, 0xaf, 0x7f, 0xaa, 0x31, 0xbb }, EXT_AUTH_KEY_ID },
72 { { 0x5c, 0x70, 0xcb, 0xf5, 0xa4, 0x07, 0x5a, 0xcc, 0xd1,
73 0x55, 0xd2, 0x44, 0xdd, 0x62, 0x2c, 0x0c }, EXT_ALT_SUBJECT_NAME },
74 { { 0 }, -1 } /* Must be last for proper termination */
78 static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp,
79 int32 len, int32 expVal,
80 v3extensions_t *extensions);
81 static int32 matrixX509ValidateCertInternal(psPool_t *pool,
82 sslCert_t *subjectCert, sslCert_t *issuerCert, int32 chain);
83 #ifdef USE_FILE_SYSTEM
84 static int32 parseList(psPool_t *pool, const char *list, const char *sep,
85 char **item);
86 #endif /* USE_FILE_SYSTEM */
88 /******************************************************************************/
90 Read in the certificate and private keys from the given files
91 If privPass is non-NULL, it will be used to decode an encrypted private
92 key file.
94 The certificate is stored internally as a pointer to DER encoded X.509
95 The private key is stored in a crypto provider specific structure
97 #ifdef USE_FILE_SYSTEM
98 int32 matrixX509ReadKeys(sslKeys_t **keys, const char *certFile,
99 const char *privFile, const char *privPass,
100 const char *trustedCAFiles)
102 return matrixX509ReadKeysEx(PEERSEC_BASE_POOL, keys, certFile, privFile,
103 privPass, trustedCAFiles);
105 #else /* USE_FILE_SYSTEM */
106 int32 matrixX509ReadKeys(sslKeys_t **keys, char *certFile, char *privFile,
107 char *privPass, char *trustedCAFile)
109 matrixStrDebugMsg("Error: Calling matrixX509ReadKeys against a library " \
110 "built without USE_FILE_SYSTEM defined\n", NULL);
111 return -1;
113 #endif /* USE_FILE_SYSTEM */
115 /******************************************************************************/
117 In memory version of matrixX509ReadKeys. The buffers are the ASN.1 raw
118 stream (ie. not base64 PEM encoded)
120 API CHANGE: 1.7 changed this protoype and buffer formats (ASN.1 now) but
121 this function was never properly documented. Users who may have found
122 this function on their own and are using it will need to convert to this
123 new version.
125 int32 matrixX509ReadKeysMem(sslKeys_t **keys, unsigned char *certBuf,
126 int32 certLen, unsigned char *privBuf, int32 privLen,
127 unsigned char *trustedCABuf, int32 trustedCALen)
129 return matrixRsaParseKeysMem(PEERSEC_BASE_POOL, keys, certBuf, certLen,
130 privBuf, privLen, trustedCABuf, trustedCALen);
133 /******************************************************************************/
135 Free private key and cert and zero memory allocated by matrixSslReadKeys.
137 void matrixRsaFreeKeys(sslKeys_t *keys)
139 sslLocalCert_t *current, *next;
140 int32 i = 0;
142 if (keys) {
143 current = &keys->cert;
144 while (current) {
145 if (current->certBin) {
146 memset(current->certBin, 0x0, current->certLen);
147 psFree(current->certBin);
149 if (current->privKey) {
150 matrixRsaFreeKey(current->privKey);
152 next = current->next;
153 if (i++ > 0) {
154 psFree(current);
156 current = next;
158 #ifdef USE_CLIENT_SIDE_SSL
159 if (keys->caCerts) {
160 matrixX509FreeCert(keys->caCerts);
162 #endif /* USE_CLIENT_SIDE_SSL */
163 psFree(keys);
167 #ifdef USE_FILE_SYSTEM
168 /******************************************************************************/
170 Preferred version for commercial users who make use of memory pools.
172 This use of the sslKeys_t param implies this is for use in the MatrixSSL
173 product (input to matrixSslNewSession). However, we didn't want to
174 expose this API at the matrixSsl.h level due to the pool parameter. This
175 is strictly an API that commerical users will have access to
177 int32 matrixX509ReadKeysEx(psPool_t *pool, sslKeys_t **keys,
178 const char *certFile, const char *privFile,
179 const char *privPass, const char *trustedCAFiles)
181 sslKeys_t *lkeys;
182 unsigned char *privKeyMem;
183 int32 rc, privKeyMemLen;
184 #ifdef USE_CLIENT_SIDE_SSL
185 sslCert_t *currCert, *prevCert = NULL;
186 unsigned char *caCert, *caStream;
187 sslChainLen_t chain;
188 int32 caCertLen, first, i;
189 #endif /* USE_CLIENT_SIDE_SSL */
191 *keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
192 if (lkeys == NULL) {
193 return -8; /* SSL_MEM_ERROR */
195 memset(lkeys, 0x0, sizeof(sslKeys_t));
197 Load certificate files. Any additional certificate files should chain
198 to the root CA held on the other side.
200 rc = readCertChain(pool, certFile, &lkeys->cert);
201 if (rc < 0 ) {
202 matrixRsaFreeKeys(lkeys);
203 return rc;
206 The first cert in certFile must be associated with the provided
207 private key.
209 if (privFile) {
210 rc = matrixX509ReadPrivKey(pool, privFile, privPass, &privKeyMem,
211 &privKeyMemLen);
212 if (rc < 0) {
213 matrixStrDebugMsg("Error reading private key file: %s\n",
214 (char*)privFile);
215 matrixRsaFreeKeys(lkeys);
216 return rc;
218 rc = matrixRsaParsePrivKey(pool, privKeyMem, privKeyMemLen,
219 &lkeys->cert.privKey);
220 if (rc < 0) {
221 matrixStrDebugMsg("Error parsing private key file: %s\n",
222 (char*)privFile);
223 psFree(privKeyMem);
224 matrixRsaFreeKeys(lkeys);
225 return rc;
227 psFree(privKeyMem);
230 #ifdef USE_CLIENT_SIDE_SSL
232 Now deal with Certificate Authorities
234 if (trustedCAFiles != NULL) {
235 if (matrixX509ReadCert(pool, trustedCAFiles, &caCert, &caCertLen,
236 &chain) < 0 || caCert == NULL) {
237 matrixStrDebugMsg("Error reading CA cert files %s\n",
238 (char*)trustedCAFiles);
239 matrixRsaFreeKeys(lkeys);
240 return -1;
243 caStream = caCert;
244 i = first = 0;
245 while (chain[i] != 0) {
247 Don't allow one bad cert to ruin the whole bunch if possible
249 if (matrixX509ParseCert(pool, caStream, chain[i], &currCert) < 0) {
250 matrixX509FreeCert(currCert);
251 matrixStrDebugMsg("Error parsing CA cert %s\n",
252 (char*)trustedCAFiles);
253 caStream += chain[i]; caCertLen -= chain[i];
254 i++;
255 continue;
258 if (first == 0) {
259 lkeys->caCerts = currCert;
260 } else {
261 prevCert->next = currCert;
263 first++;
264 prevCert = currCert;
265 currCert = NULL;
266 caStream += chain[i]; caCertLen -= chain[i];
267 i++;
269 sslAssert(caCertLen == 0);
270 psFree(caCert);
273 Check to see that if a set of CAs were passed in at least
274 one ended up being valid.
276 if (trustedCAFiles != NULL && lkeys->caCerts == NULL) {
277 matrixStrDebugMsg("No valid CA certs in %s\n",
278 (char*)trustedCAFiles);
279 matrixRsaFreeKeys(lkeys);
280 return -1;
282 #endif /* USE_CLIENT_SIDE_SSL */
283 return 0;
286 /******************************************************************************/
288 * Public API to return a binary buffer from a cert. Suitable to send
289 * over the wire. Caller must free 'out' if this function returns success (0)
290 * Parse .pem files according to http://www.faqs.org/rfcs/rfc1421.html
292 int32 matrixX509ReadCert(psPool_t *pool, const char *fileName,
293 unsigned char **out, int32 *outLen, sslChainLen_t *chain)
295 int32 certBufLen, rc, certChainLen, i;
296 unsigned char *oneCert[MAX_CHAIN_LENGTH];
297 unsigned char *certPtr, *tmp;
298 char *certFile, *start, *end, *certBuf, *endTmp;
299 const char sep[] = ";";
302 Init chain array and output params
304 for (i=0; i < MAX_CHAIN_LENGTH; i++) {
305 oneCert[i] = NULL;
306 (*chain)[i] = 0;
308 *outLen = certChainLen = i = 0;
309 rc = -1;
312 For PKI product purposes, this routine now accepts a chain of certs.
314 if (fileName != NULL) {
315 fileName += parseList(pool, fileName, sep, &certFile);
316 } else {
317 return 0;
320 while (certFile != NULL) {
322 if (i == MAX_CHAIN_LENGTH) {
323 matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
324 MAX_CHAIN_LENGTH);
325 psFree(certFile);
326 rc = -1;
327 goto err;
329 if ((rc = psGetFileBin(pool, certFile, (unsigned char**)&certBuf,
330 &certBufLen)) < 0) {
331 matrixStrDebugMsg("Couldn't open file %s\n", certFile);
332 goto err;
334 psFree(certFile);
335 certPtr = (unsigned char*)certBuf;
336 start = end = endTmp = certBuf;
338 while (certBufLen > 0) {
339 if (((start = strstr(certBuf, "-----BEGIN")) != NULL) &&
340 ((start = strstr(certBuf, "CERTIFICATE-----")) != NULL) &&
341 ((end = strstr(start, "-----END")) != NULL) &&
342 ((endTmp = strstr(end,"CERTIFICATE-----")) != NULL)) {
343 start += strlen("CERTIFICATE-----");
344 (*chain)[i] = (int32)(end - start);
345 end = endTmp + strlen("CERTIFICATE-----");
346 while (*end == '\r' || *end == '\n' || *end == '\t'
347 || *end == ' ') {
348 end++;
350 } else {
351 psFree(certPtr);
352 rc = -1;
353 goto err;
355 oneCert[i] = psMalloc(pool, (*chain)[i]);
356 certBufLen -= (int32)(end - certBuf);
357 certBuf = end;
358 memset(oneCert[i], '\0', (*chain)[i]);
360 if (ps_base64_decode((unsigned char*)start, (*chain)[i], oneCert[i],
361 &(*chain)[i]) != 0) {
362 psFree(certPtr);
363 matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL);
364 rc = -1;
365 goto err;
367 certChainLen += (*chain)[i];
368 i++;
369 if (i == MAX_CHAIN_LENGTH) {
370 matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
371 MAX_CHAIN_LENGTH);
372 psFree(certPtr);
373 rc = -1;
374 goto err;
377 psFree(certPtr);
379 Check for more files
381 fileName += parseList(pool, fileName, sep, &certFile);
384 *outLen = certChainLen;
386 Don't bother stringing them together if only one was passed in
388 if (i == 1) {
389 sslAssert(certChainLen == (*chain)[0]);
390 *out = oneCert[0];
391 return 0;
392 } else {
393 *out = tmp = psMalloc(pool, certChainLen);
394 for (i=0; i < MAX_CHAIN_LENGTH; i++) {
395 if (oneCert[i]) {
396 memcpy(tmp, oneCert[i], (*chain)[i]);
397 tmp += (*chain)[i];
400 rc = 0;
403 err:
404 for (i=0; i < MAX_CHAIN_LENGTH; i++) {
405 if (oneCert[i]) psFree(oneCert[i]);
407 return rc;
410 /******************************************************************************/
412 This function was written strictly for clarity in the PeerSec crypto API
413 product. It extracts only the public key from a certificate file for use
414 in the lower level encrypt/decrypt RSA routines
416 int32 matrixX509ReadPubKey(psPool_t *pool, const char *certFile,
417 sslRsaKey_t **key)
419 unsigned char *certBuf;
420 sslChainLen_t chain;
421 int32 certBufLen;
423 certBuf = NULL;
424 if (matrixX509ReadCert(pool, certFile, &certBuf, &certBufLen, &chain) < 0) {
425 matrixStrDebugMsg("Unable to read certificate file %s\n",
426 (char*)certFile);
427 if (certBuf) psFree(certBuf);
428 return -1;
430 if (matrixX509ParsePubKey(pool, certBuf, certBufLen, key) < 0) {
431 psFree(certBuf);
432 return -1;
434 psFree(certBuf);
435 return 0;
438 /******************************************************************************/
440 Allows for semi-colon delimited list of certificates for cert chaining.
441 Also allows multiple certificiates in a single file.
443 HOWERVER, in both cases the first in the list must be the identifying
444 cert of the application. Each subsequent cert is the parent of the previous
446 int32 readCertChain(psPool_t *pool, const char *certFiles,
447 sslLocalCert_t *lkeys)
449 sslLocalCert_t *currCert;
450 unsigned char *certBin, *tmp;
451 sslChainLen_t chain;
452 int32 certLen, i;
454 if (certFiles == NULL) {
455 return 0;
458 if (matrixX509ReadCert(pool, certFiles, &certBin, &certLen, &chain) < 0) {
459 matrixStrDebugMsg("Error reading cert file %s\n", (char*)certFiles);
460 return -1;
463 The first cert is allocated in the keys struct. All others in
464 linked list are allocated here.
466 i = 0;
467 tmp = certBin;
468 while (chain[i] != 0) {
469 if (i == 0) {
470 currCert = lkeys;
471 } else {
472 currCert->next = psMalloc(pool, sizeof(sslLocalCert_t));
473 if (currCert->next == NULL) {
474 psFree(tmp);
475 return -8; /* SSL_MEM_ERROR */
477 memset(currCert->next, 0x0, sizeof(sslLocalCert_t));
478 currCert = currCert->next;
480 currCert->certBin = psMalloc(pool, chain[i]);
481 memcpy(currCert->certBin, certBin, chain[i]);
482 currCert->certLen = chain[i];
483 certBin += chain[i]; certLen -= chain[i];
484 i++;
486 psFree(tmp);
487 sslAssert(certLen == 0);
488 return 0;
491 /******************************************************************************/
493 * Strtok substitute
495 static int32 parseList(psPool_t *pool, const char *list, const char *sep,
496 char **item)
498 int32 start, listLen;
499 char *tmp;
501 start = listLen = (int32)strlen(list) + 1;
502 if (start == 1) {
503 *item = NULL;
504 return 0;
506 tmp = *item = psMalloc(pool, listLen);
507 if (tmp == NULL) {
508 return -8; /* SSL_MEM_ERROR */
510 memset(*item, 0, listLen);
511 while (listLen > 0) {
512 if (*list == sep[0]) {
513 list++;
514 listLen--;
515 break;
517 if (*list == 0) {
518 break;
520 *tmp++ = *list++;
521 listLen--;
523 return start - listLen;
525 #endif /* USE_FILE_SYSTEM */
528 /******************************************************************************/
530 Preferred version for commercial users who make use of memory pools.
532 This use of the sslKeys_t param implies this is for use in the MatrixSSL
533 product (input to matrixSslNewSession). However, we didn't want to
534 expose this API at the matrixSsl.h level due to the pool parameter. This
535 is strictly an API that commerical users will have access to.
537 int32 matrixRsaParseKeysMem(psPool_t *pool, sslKeys_t **keys,
538 unsigned char *certBuf, int32 certLen, unsigned char *privBuf,
539 int32 privLen, unsigned char *trustedCABuf, int32 trustedCALen)
541 sslKeys_t *lkeys;
542 sslLocalCert_t *current, *next;
543 unsigned char *binPtr;
544 int32 len, lenOh, i;
545 #ifdef USE_CLIENT_SIDE_SSL
546 sslCert_t *currentCA, *nextCA;
547 #endif /* USE_CLIENT_SIDE_SSL */
549 *keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
550 if (lkeys == NULL) {
551 return -8; /* SSL_MEM_ERROR */
553 memset(lkeys, 0x0, sizeof(sslKeys_t));
555 The buffers are just the ASN.1 streams so the intermediate parse
556 that used to be here is gone. Doing a straight memcpy for this
557 and passing that along to X509ParseCert
559 i = 0;
560 current = &lkeys->cert;
561 binPtr = certBuf;
563 Need to check for a chain here. Only way to do this is to read off the
564 length id from the DER stream for each. The chain must be just a stream
565 of DER certs with the child-most cert always first.
567 while (certLen > 0) {
568 if (getSequence(&certBuf, certLen, &len) < 0) {
569 matrixStrDebugMsg("Unable to parse length of cert stream\n", NULL);
570 matrixRsaFreeKeys(lkeys);
571 return -1;
574 Account for the overhead of storing the length itself
576 lenOh = (int32)(certBuf - binPtr);
577 len += lenOh;
578 certBuf -= lenOh;
580 First cert is already malloced
582 if (i > 0) {
583 next = psMalloc(pool, sizeof(sslLocalCert_t));
584 memset(next, 0x0, sizeof(sslLocalCert_t));
585 current->next = next;
586 current = next;
588 current->certBin = psMalloc(pool, len);
589 memcpy(current->certBin, certBuf, len);
590 current->certLen = len;
591 certLen -= len;
592 certBuf += len;
593 binPtr = certBuf;
594 i++;
598 Parse private key
600 if (privLen > 0) {
601 if (matrixRsaParsePrivKey(pool, privBuf, privLen,
602 &lkeys->cert.privKey) < 0) {
603 matrixStrDebugMsg("Error reading private key mem\n", NULL);
604 matrixRsaFreeKeys(lkeys);
605 return -1;
611 Trusted CAs
613 #ifdef USE_CLIENT_SIDE_SSL
614 if (trustedCABuf != NULL && trustedCALen > 0) {
615 i = 0;
616 binPtr = trustedCABuf;
617 currentCA = NULL;
619 Need to check for list here. Only way to do this is to read off the
620 length id from the DER stream for each.
622 while (trustedCALen > 0) {
623 if (getSequence(&trustedCABuf, trustedCALen, &len) < 0) {
624 matrixStrDebugMsg("Unable to parse length of CA stream\n",
625 NULL);
626 matrixRsaFreeKeys(lkeys);
627 return -1;
630 Account for the overhead of storing the length itself
632 lenOh = (int32)(trustedCABuf - binPtr);
633 len += lenOh;
634 trustedCABuf -= lenOh;
636 if (matrixX509ParseCert(pool, trustedCABuf, len, &currentCA) < 0) {
637 matrixX509FreeCert(currentCA);
638 matrixStrDebugMsg("Error parsing CA cert\n", NULL);
639 matrixRsaFreeKeys(lkeys);
640 return -1;
643 First cert should be assigned to lkeys
645 if (i == 0) {
646 lkeys->caCerts = currentCA;
647 nextCA = lkeys->caCerts;
648 } else {
649 nextCA->next = currentCA;
650 nextCA = currentCA;
652 currentCA = currentCA->next;
653 trustedCALen -= len;
654 trustedCABuf += len;
655 binPtr = trustedCABuf;
656 i++;
659 #endif /* USE_CLIENT_SIDE_SSL */
661 return 0;
664 /******************************************************************************/
666 In-memory version of matrixX509ReadPubKey.
667 This function was written strictly for clarity in the PeerSec crypto API
668 subset. It extracts only the public key from a certificate file for use
669 in the lower level encrypt/decrypt RSA routines.
671 int32 matrixX509ParsePubKey(psPool_t *pool, unsigned char *certBuf,
672 int32 certLen, sslRsaKey_t **key)
674 sslRsaKey_t *lkey;
675 sslCert_t *certStruct;
676 int32 err;
678 if (matrixX509ParseCert(pool, certBuf, certLen, &certStruct) < 0) {
679 matrixX509FreeCert(certStruct);
680 return -1;
682 lkey = *key = psMalloc(pool, sizeof(sslRsaKey_t));
683 memset(lkey, 0x0, sizeof(sslRsaKey_t));
685 if ((err = _mp_init_multi(pool, &lkey->e, &lkey->N, NULL,
686 NULL, NULL, NULL, NULL, NULL)) != MP_OKAY) {
687 matrixX509FreeCert(certStruct);
688 psFree(lkey);
689 return err;
691 mp_copy(&certStruct->publicKey.e, &lkey->e);
692 mp_copy(&certStruct->publicKey.N, &lkey->N);
694 mp_shrink(&lkey->e);
695 mp_shrink(&lkey->N);
697 lkey->size = certStruct->publicKey.size;
699 matrixX509FreeCert(certStruct);
701 return 0;
705 /******************************************************************************/
707 Parse an X509 ASN.1 certificate stream
708 http://www.faqs.org/rfcs/rfc2459.html section 4.1
710 int32 matrixX509ParseCert(psPool_t *pool, unsigned char *pp, int32 size,
711 sslCert_t **outcert)
713 sslCert_t *cert;
714 sslMd5Context_t md5Ctx;
715 sslSha1Context_t sha1Ctx;
716 unsigned char *p, *end, *certStart, *certEnd;
717 int32 certLen, len, parsing;
718 #ifdef USE_MD2
719 sslMd2Context_t md2Ctx;
720 #endif /* USE_MD2 */
723 Allocate the cert structure right away. User MUST always call
724 matrixX509FreeCert regardless of whether this function succeeds.
725 memset is important because the test for NULL is what is used
726 to determine what to free
728 *outcert = cert = psMalloc(pool, sizeof(sslCert_t));
729 if (cert == NULL) {
730 return -8; /* SSL_MEM_ERROR */
732 memset(cert, '\0', sizeof(sslCert_t));
734 p = pp;
735 end = p + size;
737 Certificate ::= SEQUENCE {
738 tbsCertificate TBSCertificate,
739 signatureAlgorithm AlgorithmIdentifier,
740 signatureValue BIT STRING }
742 parsing = 1;
743 while (parsing) {
744 if (getSequence(&p, (int32)(end - p), &len) < 0) {
745 matrixStrDebugMsg("Initial cert parse error\n", NULL);
746 return -1;
748 certStart = p;
750 TBSCertificate ::= SEQUENCE {
751 version [0] EXPLICIT Version DEFAULT v1,
752 serialNumber CertificateSerialNumber,
753 signature AlgorithmIdentifier,
754 issuer Name,
755 validity Validity,
756 subject Name,
757 subjectPublicKeyInfo SubjectPublicKeyInfo,
758 issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
759 -- If present, version shall be v2 or v3
760 subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
761 -- If present, version shall be v2 or v3
762 extensions [3] EXPLICIT Extensions OPTIONAL
763 -- If present, version shall be v3 }
765 if (getSequence(&p, (int32)(end - p), &len) < 0) {
766 matrixStrDebugMsg("ASN sequence parse error\n", NULL);
767 return -1;
769 certEnd = p + len;
770 certLen = (int32)(certEnd - certStart);
773 Version ::= INTEGER { v1(0), v2(1), v3(2) }
775 if (getExplicitVersion(&p, (int32)(end - p), 0, &cert->version) < 0) {
776 matrixStrDebugMsg("ASN version parse error\n", NULL);
777 return -1;
779 if (cert->version != 2) {
780 matrixIntDebugMsg("Warning: non-v3 certificate version: %d\n",
781 cert->version);
784 CertificateSerialNumber ::= INTEGER
786 if (getSerialNum(pool, &p, (int32)(end - p), &cert->serialNumber,
787 &cert->serialNumberLen) < 0) {
788 matrixStrDebugMsg("ASN serial number parse error\n", NULL);
789 return -1;
792 AlgorithmIdentifier ::= SEQUENCE {
793 algorithm OBJECT IDENTIFIER,
794 parameters ANY DEFINED BY algorithm OPTIONAL }
796 if (getAlgorithmIdentifier(&p, (int32)(end - p),
797 &cert->certAlgorithm, 0) < 0) {
798 return -1;
801 Name ::= CHOICE {
802 RDNSequence }
804 RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
806 RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
808 AttributeTypeAndValue ::= SEQUENCE {
809 type AttributeType,
810 value AttributeValue }
812 AttributeType ::= OBJECT IDENTIFIER
814 AttributeValue ::= ANY DEFINED BY AttributeType
816 if (getDNAttributes(pool, &p, (int32)(end - p), &cert->issuer) < 0) {
817 return -1;
820 Validity ::= SEQUENCE {
821 notBefore Time,
822 notAfter Time }
824 if (getValidity(pool, &p, (int32)(end - p), &cert->notBefore,
825 &cert->notAfter) < 0) {
826 return -1;
829 Subject DN
831 if (getDNAttributes(pool, &p, (int32)(end - p), &cert->subject) < 0) {
832 return -1;
835 SubjectPublicKeyInfo ::= SEQUENCE {
836 algorithm AlgorithmIdentifier,
837 subjectPublicKey BIT STRING }
839 if (getSequence(&p, (int32)(end - p), &len) < 0) {
840 return -1;
842 if (getAlgorithmIdentifier(&p, (int32)(end - p),
843 &cert->pubKeyAlgorithm, 1) < 0) {
844 return -1;
847 if (getPubKey(pool, &p, (int32)(end - p), &cert->publicKey) < 0) {
848 return -1;
852 As the next three values are optional, we can do a specific test here
854 if (*p != (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
855 if (getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_ISSUER_ID,
856 &cert->uniqueUserId, &cert->uniqueUserIdLen) < 0 ||
857 getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_SUBJECT_ID,
858 &cert->uniqueSubjectId, &cert->uniqueSubjectIdLen) < 0 ||
859 getExplicitExtensions(pool, &p, (int32)(end - p), EXPLICIT_EXTENSION,
860 &cert->extensions) < 0) {
861 matrixStrDebugMsg("There was an error parsing a certificate\n", NULL);
862 matrixStrDebugMsg("extension. This is likely caused by an\n", NULL);
863 matrixStrDebugMsg("extension format that is not currently\n", NULL);
864 matrixStrDebugMsg("recognized. Please email support@peersec.com\n", NULL);
865 matrixStrDebugMsg("to add support for the extension.\n\n", NULL);
866 return -1;
870 This is the end of the cert. Do a check here to be certain
872 if (certEnd != p) {
873 return -1;
876 Certificate signature info
878 if (getAlgorithmIdentifier(&p, (int32)(end - p),
879 &cert->sigAlgorithm, 0) < 0) {
880 return -1;
883 Signature algorithm must match that specified in TBS cert
885 if (cert->certAlgorithm != cert->sigAlgorithm) {
886 matrixStrDebugMsg("Parse error: mismatched signature type\n", NULL);
887 return -1;
890 Compute the hash of the cert here for CA validation
892 if (cert->certAlgorithm == OID_RSA_MD5) {
893 matrixMd5Init(&md5Ctx);
894 matrixMd5Update(&md5Ctx, certStart, certLen);
895 matrixMd5Final(&md5Ctx, cert->sigHash);
896 } else if (cert->certAlgorithm == OID_RSA_SHA1) {
897 matrixSha1Init(&sha1Ctx);
898 matrixSha1Update(&sha1Ctx, certStart, certLen);
899 matrixSha1Final(&sha1Ctx, cert->sigHash);
901 #ifdef USE_MD2
902 else if (cert->certAlgorithm == OID_RSA_MD2) {
903 matrixMd2Init(&md2Ctx);
904 matrixMd2Update(&md2Ctx, certStart, certLen);
905 matrixMd2Final(&md2Ctx, cert->sigHash);
907 #endif /* USE_MD2 */
909 if (getSignature(pool, &p, (int32)(end - p), &cert->signature,
910 &cert->signatureLen) < 0) {
911 return -1;
914 The ability to parse additional chained certs is a PKI product
915 feature addition. Chaining in MatrixSSL is handled internally.
917 if (p != end) {
918 cert->next = psMalloc(pool, sizeof(sslCert_t));
919 cert = cert->next;
920 memset(cert, '\0', sizeof(sslCert_t));
921 } else {
922 parsing = 0;
926 return (int32)(p - pp);
929 /******************************************************************************/
931 User must call after all calls to matrixX509ParseCert
932 (we violate the coding standard a bit here for clarity)
934 void matrixX509FreeCert(sslCert_t *cert)
936 sslCert_t *curr, *next;
937 sslSubjectAltName_t *active, *inc;
939 curr = cert;
940 while (curr) {
941 psFreeDNStruct(&curr->issuer);
942 psFreeDNStruct(&curr->subject);
943 if (curr->serialNumber) psFree(curr->serialNumber);
944 if (curr->notBefore) psFree(curr->notBefore);
945 if (curr->notAfter) psFree(curr->notAfter);
946 if (curr->publicKey.N.dp) mp_clear(&(curr->publicKey.N));
947 if (curr->publicKey.e.dp) mp_clear(&(curr->publicKey.e));
948 if (curr->signature) psFree(curr->signature);
949 if (curr->uniqueUserId) psFree(curr->uniqueUserId);
950 if (curr->uniqueSubjectId) psFree(curr->uniqueSubjectId);
952 if (curr->extensions.san) {
953 active = curr->extensions.san;
954 while (active != NULL) {
955 inc = active->next;
956 psFree(active->data);
957 psFree(active);
958 active = inc;
963 #ifdef USE_FULL_CERT_PARSE
964 if (curr->extensions.keyUsage) psFree(curr->extensions.keyUsage);
965 if (curr->extensions.sk.id) psFree(curr->extensions.sk.id);
966 if (curr->extensions.ak.keyId) psFree(curr->extensions.ak.keyId);
967 if (curr->extensions.ak.serialNum)
968 psFree(curr->extensions.ak.serialNum);
969 if (curr->extensions.ak.attribs.commonName)
970 psFree(curr->extensions.ak.attribs.commonName);
971 if (curr->extensions.ak.attribs.country)
972 psFree(curr->extensions.ak.attribs.country);
973 if (curr->extensions.ak.attribs.state)
974 psFree(curr->extensions.ak.attribs.state);
975 if (curr->extensions.ak.attribs.locality)
976 psFree(curr->extensions.ak.attribs.locality);
977 if (curr->extensions.ak.attribs.organization)
978 psFree(curr->extensions.ak.attribs.organization);
979 if (curr->extensions.ak.attribs.orgUnit)
980 psFree(curr->extensions.ak.attribs.orgUnit);
981 #endif /* SSL_FULL_CERT_PARSE */
982 next = curr->next;
983 psFree(curr);
984 curr = next;
988 /******************************************************************************/
990 Do the signature validation for a subject certificate against a
991 known CA certificate
993 int32 psAsnConfirmSignature(unsigned char *sigHash, unsigned char *sigOut,
994 int32 sigLen)
996 unsigned char *end, *p = sigOut;
997 unsigned char hash[SSL_SHA1_HASH_SIZE];
998 int32 len, oi;
1000 end = p + sigLen;
1002 DigestInfo ::= SEQUENCE {
1003 digestAlgorithm DigestAlgorithmIdentifier,
1004 digest Digest }
1006 DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1008 Digest ::= OCTET STRING
1010 if (getSequence(&p, (int32)(end - p), &len) < 0) {
1011 return -1;
1015 Could be MD5 or SHA1
1017 if (getAlgorithmIdentifier(&p, (int32)(end - p), &oi, 0) < 0) {
1018 return -1;
1020 if ((*p++ != ASN_OCTET_STRING) ||
1021 asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) < len) {
1022 return -1;
1024 memcpy(hash, p, len);
1025 if (oi == OID_MD5 || oi == OID_MD2) {
1026 if (len != SSL_MD5_HASH_SIZE) {
1027 return -1;
1029 } else if (oi == OID_SHA1) {
1030 if (len != SSL_SHA1_HASH_SIZE) {
1031 return -1;
1033 } else {
1034 return -1;
1037 hash should match sigHash
1039 if (memcmp(hash, sigHash, len) != 0) {
1040 return -1;
1042 return 0;
1045 /******************************************************************************/
1047 Extension lookup
1049 static int32 lookupExt(unsigned char md5hash[SSL_MD5_HASH_SIZE])
1051 int32 i, j;
1052 const unsigned char *tmp;
1054 for (i = 0; ;i++) {
1055 if (extTable[i].id == -1) {
1056 return -1;
1058 tmp = extTable[i].hash;
1059 for (j = 0; j < SSL_MD5_HASH_SIZE; j++) {
1060 if (md5hash[j] != tmp[j]) {
1061 break;
1063 if (j == SSL_MD5_HASH_SIZE - 1) {
1064 return extTable[i].id;
1070 /******************************************************************************/
1072 X509v3 extensions
1074 static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp,
1075 int32 inlen, int32 expVal,
1076 v3extensions_t *extensions)
1078 unsigned char *p = *pp, *end;
1079 unsigned char *extEnd, *extStart;
1080 int32 len, noid, critical, fullExtLen;
1081 unsigned char oid[SSL_MD5_HASH_SIZE];
1082 sslMd5Context_t md5ctx;
1083 sslSubjectAltName_t *activeName, *prevName;
1085 end = p + inlen;
1086 if (inlen < 1) {
1087 return -1;
1090 Not treating this as an error because it is optional.
1092 if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | expVal)) {
1093 return 0;
1095 p++;
1096 if (asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) < len) {
1097 return -1;
1100 Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
1102 Extension ::= SEQUENCE {
1103 extnID OBJECT IDENTIFIER,
1104 extnValue OCTET STRING }
1106 if (getSequence(&p, (int32)(end - p), &len) < 0) {
1107 return -1;
1109 extEnd = p + len;
1110 while ((p != extEnd) && *p == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
1111 if (getSequence(&p, (int32)(extEnd - p), &fullExtLen) < 0) {
1112 return -1;
1114 extStart = p;
1116 Conforming CAs MUST support key identifiers, basic constraints,
1117 key usage, and certificate policies extensions
1119 id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
1120 id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } 133
1121 id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
1122 id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
1123 id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } 131
1125 if (extEnd - p < 1 || *p++ != ASN_OID) {
1126 return -1;
1129 if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
1130 (extEnd - p) < len) {
1131 return -1;
1134 Send the OID through a digest to get the unique id
1136 matrixMd5Init(&md5ctx);
1137 while (len-- > 0) {
1138 matrixMd5Update(&md5ctx, p, sizeof(char));
1139 p++;
1141 matrixMd5Final(&md5ctx, oid);
1142 noid = lookupExt(oid);
1145 Possible boolean value here for 'critical' id. It's a failure if a
1146 critical extension is found that is not supported
1148 critical = 0;
1149 if (*p == ASN_BOOLEAN) {
1150 p++;
1151 if (*p++ != 1) {
1152 matrixStrDebugMsg("Error parsing cert extension\n", NULL);
1153 return -1;
1155 if (*p++ > 0) {
1156 critical = 1;
1159 if (extEnd - p < 1 || (*p++ != ASN_OCTET_STRING) ||
1160 asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
1161 extEnd - p < len) {
1162 matrixStrDebugMsg("Expecting OCTET STRING in ext parse\n", NULL);
1163 return -1;
1166 switch (noid) {
1168 BasicConstraints ::= SEQUENCE {
1169 cA BOOLEAN DEFAULT FALSE,
1170 pathLenConstraint INTEGER (0..MAX) OPTIONAL }
1172 case EXT_BASIC_CONSTRAINTS:
1173 if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
1174 return -1;
1177 "This goes against PKIX guidelines but some CAs do it and some
1178 software requires this to avoid interpreting an end user
1179 certificate as a CA."
1180 - OpenSSL certificate configuration doc
1182 basicConstraints=CA:FALSE
1184 if (len == 0) {
1185 break;
1188 Have seen some certs that don't include a cA bool.
1190 if (*p == ASN_BOOLEAN) {
1191 p++;
1192 if (*p++ != 1) {
1193 return -1;
1195 extensions->bc.ca = *p++;
1196 } else {
1197 extensions->bc.ca = 0;
1200 Now need to check if there is a path constraint. Only makes
1201 sense if cA is true. If it's missing, there is no limit to
1202 the cert path
1204 if (*p == ASN_INTEGER) {
1205 if (getInteger(&p, (int32)(extEnd - p),
1206 &(extensions->bc.pathLenConstraint)) < 0) {
1207 return -1;
1209 } else {
1210 extensions->bc.pathLenConstraint = -1;
1212 break;
1213 case EXT_ALT_SUBJECT_NAME:
1214 if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
1215 return -1;
1218 Looking only for DNS, URI, and email here to support
1219 FQDN for Web clients
1221 FUTURE: Support all subject alt name members
1222 GeneralName ::= CHOICE {
1223 otherName [0] OtherName,
1224 rfc822Name [1] IA5String,
1225 dNSName [2] IA5String,
1226 x400Address [3] ORAddress,
1227 directoryName [4] Name,
1228 ediPartyName [5] EDIPartyName,
1229 uniformResourceIdentifier [6] IA5String,
1230 iPAddress [7] OCTET STRING,
1231 registeredID [8] OBJECT IDENTIFIER }
1233 while (len > 0) {
1234 if (extensions->san == NULL) {
1235 activeName = extensions->san = psMalloc(pool,
1236 sizeof(sslSubjectAltName_t));
1237 } else {
1239 Find the end
1241 prevName = extensions->san;
1242 activeName = prevName->next;
1243 while (activeName != NULL) {
1244 prevName = activeName;
1245 activeName = prevName->next;
1247 prevName->next = psMalloc(pool,
1248 sizeof(sslSubjectAltName_t));
1249 activeName = prevName->next;
1251 activeName->next = NULL;
1252 activeName->data = NULL;
1253 memset(activeName->name, '\0', 16);
1255 activeName->id = *p & 0xF;
1256 switch (activeName->id) {
1257 case 0:
1258 memcpy(activeName->name, "other", 5);
1259 break;
1260 case 1:
1261 memcpy(activeName->name, "email", 5);
1262 break;
1263 case 2:
1264 memcpy(activeName->name, "DNS", 3);
1265 break;
1266 case 3:
1267 memcpy(activeName->name, "x400Address", 11);
1268 break;
1269 case 4:
1270 memcpy(activeName->name, "directoryName", 13);
1271 break;
1272 case 5:
1273 memcpy(activeName->name, "ediPartyName", 12);
1274 break;
1275 case 6:
1276 memcpy(activeName->name, "URI", 3);
1277 break;
1278 case 7:
1279 memcpy(activeName->name, "iPAddress", 9);
1280 break;
1281 case 8:
1282 memcpy(activeName->name, "registeredID", 12);
1283 break;
1284 default:
1285 memcpy(activeName->name, "unknown", 7);
1286 break;
1289 p++;
1290 activeName->dataLen = *p++;
1291 if (extEnd - p < activeName->dataLen) {
1292 return -1;
1294 activeName->data = psMalloc(pool, activeName->dataLen + 1);
1295 if (activeName->data == NULL) {
1296 return -8; /* SSL_MEM_ERROR */
1298 memset(activeName->data, 0x0, activeName->dataLen + 1);
1299 memcpy(activeName->data, p, activeName->dataLen);
1301 p = p + activeName->dataLen;
1302 /* the magic 2 is the type and length */
1303 len -= activeName->dataLen + 2;
1305 break;
1306 #ifdef USE_FULL_CERT_PARSE
1307 case EXT_AUTH_KEY_ID:
1309 AuthorityKeyIdentifier ::= SEQUENCE {
1310 keyIdentifier [0] KeyIdentifier OPTIONAL,
1311 authorityCertIssuer [1] GeneralNames OPTIONAL,
1312 authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
1314 KeyIdentifier ::= OCTET STRING
1316 if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
1317 return -1;
1320 Have seen a cert that has a zero length ext here. Let it pass.
1322 if (len == 0) {
1323 break;
1326 All memebers are optional
1328 if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 0)) {
1329 p++;
1330 if (asnParseLength(&p, (int32)(extEnd - p),
1331 &extensions->ak.keyLen) < 0 ||
1332 extEnd - p < extensions->ak.keyLen) {
1333 return -1;
1335 extensions->ak.keyId = psMalloc(pool, extensions->ak.keyLen);
1336 if (extensions->ak.keyId == NULL) {
1337 return -8; /* SSL_MEM_ERROR */
1339 memcpy(extensions->ak.keyId, p, extensions->ak.keyLen);
1340 p = p + extensions->ak.keyLen;
1342 if (*p == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) {
1343 p++;
1344 if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
1345 len < 1 || extEnd - p < len) {
1346 return -1;
1348 if ((*p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED) != 4) {
1350 FUTURE: support other name types
1351 We are just dealing with DN formats here
1353 matrixIntDebugMsg("Error auth key-id name type: %d\n",
1354 *p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED);
1355 return -1;
1357 p++;
1358 if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
1359 extEnd - p < len) {
1360 return -1;
1362 if (getDNAttributes(pool, &p, (int32)(extEnd - p),
1363 &(extensions->ak.attribs)) < 0) {
1364 return -1;
1367 if ((*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) ||
1368 (*p == ASN_INTEGER)){
1370 Treat as a serial number (not a native INTEGER)
1372 if (getSerialNum(pool, &p, (int32)(extEnd - p),
1373 &(extensions->ak.serialNum), &len) < 0) {
1374 return -1;
1376 extensions->ak.serialNumLen = len;
1378 break;
1380 case EXT_KEY_USAGE:
1382 KeyUsage ::= BIT STRING {
1383 digitalSignature (0),
1384 nonRepudiation (1),
1385 keyEncipherment (2),
1386 dataEncipherment (3),
1387 keyAgreement (4),
1388 keyCertSign (5),
1390 cRLSign (6),
1391 encipherOnly (7),
1392 decipherOnly (8) }
1394 if (*p++ != ASN_BIT_STRING) {
1395 return -1;
1397 if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
1398 extEnd - p < len) {
1399 return -1;
1402 We'd expect a length of 3 with the first byte being '07' to
1403 account for the trailing ignore bits in the second byte.
1404 But it doesn't appear all certificates adhere to the ASN.1
1405 encoding standard very closely. Just set it all aside for
1406 user to interpret as necessary.
1408 extensions->keyUsage = psMalloc(pool, len);
1409 memcpy(extensions->keyUsage, p, len);
1410 extensions->keyUsageLen = len;
1411 p = p + len;
1412 break;
1413 case EXT_SUBJ_KEY_ID:
1415 The value of the subject key identifier MUST be the value
1416 placed in the key identifier field of the Auth Key Identifier
1417 extension of certificates issued by the subject of
1418 this certificate.
1420 if (*p++ != ASN_OCTET_STRING || asnParseLength(&p,
1421 (int32)(extEnd - p), &(extensions->sk.len)) < 0 ||
1422 extEnd - p < extensions->sk.len) {
1423 return -1;
1425 extensions->sk.id = psMalloc(pool, extensions->sk.len);
1426 if (extensions->sk.id == NULL) {
1427 return -8; /* SSL_MEM_ERROR */
1429 memcpy(extensions->sk.id, p, extensions->sk.len);
1430 p = p + extensions->sk.len;
1431 break;
1432 #endif /* USE_FULL_CERT_PARSE */
1434 Unsupported or skipping because USE_FULL_CERT_PARSE is undefined
1436 default:
1437 if (critical) {
1439 SPEC DIFFERENCE: Ignoring an unrecognized critical
1440 extension. The specification dictates an error should
1441 occur, but real-world experience has shown this is not
1442 a realistic or desirable action. Also, no other SSL
1443 implementations have been found to error in this case.
1444 It is NOT a security risk in an RSA authenticaion sense.
1446 matrixStrDebugMsg("Unknown critical ext encountered\n",
1447 NULL);
1449 p++;
1451 Skip over based on the length reported from the ASN_SEQUENCE
1452 surrounding the entire extension. It is not a guarantee that
1453 the value of the extension itself will contain it's own length.
1455 p = p + (fullExtLen - (p - extStart));
1456 break;
1459 *pp = p;
1460 return 0;
1463 /******************************************************************************/
1465 Walk through the certificate chain and validate it. Return the final
1466 member of the chain as the subjectCert that can then be validated against
1467 the CAs. The subjectCert points into the chain param (no need to free)
1469 int32 matrixX509ValidateCertChain(psPool_t *pool, sslCert_t *chain,
1470 sslCert_t **subjectCert, int32 *valid)
1472 sslCert_t *ic;
1474 *subjectCert = chain;
1475 *valid = 1;
1476 while ((*subjectCert)->next != NULL) {
1477 ic = (*subjectCert)->next;
1478 if (matrixX509ValidateCertInternal(pool, *subjectCert, ic, 1) < 0) {
1479 *valid = -1;
1480 return -1;
1483 If any portion is invalid, it's all invalid
1485 if ((*subjectCert)->valid != 1) {
1486 *valid = -1;
1488 *subjectCert = (*subjectCert)->next;
1490 return 0;
1493 /******************************************************************************/
1495 A signature validation for certificates. -1 return is an error. The success
1496 of the validation is returned in the 'valid' param of the subjectCert.
1497 1 if the issuerCert signed the subject cert. -1 if not
1499 int32 matrixX509ValidateCert(psPool_t *pool, sslCert_t *subjectCert,
1500 sslCert_t *issuerCert, int32 *valid)
1502 if (matrixX509ValidateCertInternal(pool, subjectCert, issuerCert, 0) < 0) {
1503 *valid = -1;
1504 return -1;
1506 *valid = subjectCert->valid;
1507 return 0;
1510 static int32 matrixX509ValidateCertInternal(psPool_t *pool,
1511 sslCert_t *subjectCert, sslCert_t *issuerCert, int32 chain)
1513 sslCert_t *ic;
1514 unsigned char sigOut[10 + SSL_SHA1_HASH_SIZE + 5]; /* See below */
1515 int32 sigLen, sigType, rc;
1517 subjectCert->valid = -1;
1519 Supporting a one level chain or a self-signed cert. If the issuer
1520 is NULL, the self-signed test is done.
1522 if (issuerCert == NULL) {
1523 matrixStrDebugMsg("Warning: No CA to validate cert with\n", NULL);
1524 matrixStrDebugMsg("\tPerforming self-signed CA test\n", NULL);
1525 ic = subjectCert;
1526 } else {
1527 ic = issuerCert;
1530 Path confirmation. If this is a chain verification, do not allow
1531 any holes in the path. Error out if issuer does not have CA permissions
1532 or if hashes do not match anywhere along the way.
1534 while (ic) {
1535 if (subjectCert != ic) {
1537 Certificate authority constraint only available in version 3 certs
1539 if ((ic->version > 1) && (ic->extensions.bc.ca <= 0)) {
1540 if (chain) {
1541 return -1;
1543 ic = ic->next;
1544 continue;
1547 Use sha1 hash of issuer fields computed at parse time to compare
1549 if (memcmp(subjectCert->issuer.hash, ic->subject.hash,
1550 SSL_SHA1_HASH_SIZE) != 0) {
1551 if (chain) {
1552 return -1;
1554 ic = ic->next;
1555 continue;
1559 Signature confirmation
1560 The sigLen is the ASN.1 size in bytes for encoding the hash.
1561 The magic 10 is comprised of the SEQUENCE and ALGORITHM ID overhead.
1562 The magic 8 and 5 are the OID lengths of the corresponding algorithm.
1563 NOTE: if sigLen is modified, above sigOut static size must be changed
1565 if (subjectCert->sigAlgorithm == OID_RSA_MD5 ||
1566 subjectCert->sigAlgorithm == OID_RSA_MD2) {
1567 sigType = RSA_SIG;
1568 sigLen = 10 + SSL_MD5_HASH_SIZE + 8; /* See above */
1569 } else if (subjectCert->sigAlgorithm == OID_RSA_SHA1) {
1570 sigLen = 10 + SSL_SHA1_HASH_SIZE + 5; /* See above */
1571 sigType = RSA_SIG;
1572 } else {
1573 matrixStrDebugMsg("Unsupported signature algorithm\n", NULL);
1574 return -1;
1577 if (sigType == RSA_SIG) {
1578 sslAssert(sigLen <= sizeof(sigOut));
1580 /* note: on error & no CA, flag as invalid, but don't exit as error here (<1.8.7? behavior) -- zzz */
1581 if (matrixRsaDecryptPub(pool, &(ic->publicKey),
1582 subjectCert->signature, subjectCert->signatureLen, sigOut,
1583 sigLen) < 0) {
1584 matrixStrDebugMsg("Unable to RSA decrypt signature\n", NULL);
1585 if (issuerCert) return -1;
1586 rc = -1;
1587 } else {
1588 rc = psAsnConfirmSignature(subjectCert->sigHash, sigOut, sigLen);
1592 If this is a chain test, fail on any gaps in the chain
1594 if (rc < 0) {
1595 if (chain) {
1596 return -1;
1598 ic = ic->next;
1599 continue;
1602 Fall through to here only if passed signature check.
1604 subjectCert->valid = 1;
1605 break;
1607 return 0;
1610 /******************************************************************************/
1612 Calls a user defined callback to allow for manual validation of the
1613 certificate.
1615 int32 matrixX509UserValidator(psPool_t *pool, sslCert_t *subjectCert,
1616 int32 (*certValidator)(sslCertInfo_t *t, void *arg), void *arg)
1618 sslCertInfo_t *cert, *current, *next;
1619 int32 rc;
1621 if (certValidator == NULL) {
1622 return 0;
1625 Pass the entire certificate chain to the user callback.
1627 current = cert = psMalloc(pool, sizeof(sslCertInfo_t));
1628 if (current == NULL) {
1629 return -8; /* SSL_MEM_ERROR */
1631 memset(cert, 0x0, sizeof(sslCertInfo_t));
1632 while (subjectCert) {
1634 current->issuer.commonName = subjectCert->issuer.commonName;
1635 current->issuer.country = subjectCert->issuer.country;
1636 current->issuer.locality = subjectCert->issuer.locality;
1637 current->issuer.organization = subjectCert->issuer.organization;
1638 current->issuer.orgUnit = subjectCert->issuer.orgUnit;
1639 current->issuer.state = subjectCert->issuer.state;
1641 current->subject.commonName = subjectCert->subject.commonName;
1642 current->subject.country = subjectCert->subject.country;
1643 current->subject.locality = subjectCert->subject.locality;
1644 current->subject.organization = subjectCert->subject.organization;
1645 current->subject.orgUnit = subjectCert->subject.orgUnit;
1646 current->subject.state = subjectCert->subject.state;
1648 current->serialNumber = subjectCert->serialNumber;
1649 current->serialNumberLen = subjectCert->serialNumberLen;
1650 current->verified = subjectCert->valid;
1651 current->notBefore = subjectCert->notBefore;
1652 current->notAfter = subjectCert->notAfter;
1654 current->subjectAltName = subjectCert->extensions.san;
1656 if (subjectCert->certAlgorithm == OID_RSA_MD5 ||
1657 subjectCert->certAlgorithm == OID_RSA_MD2) {
1658 current->sigHashLen = SSL_MD5_HASH_SIZE;
1659 } else if (subjectCert->certAlgorithm == OID_RSA_SHA1) {
1660 current->sigHashLen = SSL_SHA1_HASH_SIZE;
1662 current->sigHash = (char*)subjectCert->sigHash;
1663 if (subjectCert->next) {
1664 next = psMalloc(pool, sizeof(sslCertInfo_t));
1665 if (next == NULL) {
1666 while (cert) {
1667 next = cert->next;
1668 psFree(cert);
1669 cert = next;
1671 return -8; /* SSL_MEM_ERROR */
1673 memset(next, 0x0, sizeof(sslCertInfo_t));
1674 current->next = next;
1675 current = next;
1677 subjectCert = subjectCert->next;
1680 The user callback
1682 rc = certValidator(cert, arg);
1684 Free the chain
1686 while (cert) {
1687 next = cert->next;
1688 psFree(cert);
1689 cert = next;
1691 return rc;
1693 #endif /* USE_X509 */
1694 #endif /* USE_RSA */
1697 /******************************************************************************/