3 * Release $Name: MATRIXSSL_1_8_8_OPEN $
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
40 #define IMPLICIT_ISSUER_ID 1
41 #define IMPLICIT_SUBJECT_ID 2
42 #define EXPLICIT_EXTENSION 3
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
61 unsigned char hash
[16];
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
,
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
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
);
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
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
;
143 current
= &keys
->cert
;
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
;
158 #ifdef USE_CLIENT_SIDE_SSL
160 matrixX509FreeCert(keys
->caCerts
);
162 #endif /* USE_CLIENT_SIDE_SSL */
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
)
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
;
188 int32 caCertLen
, first
, i
;
189 #endif /* USE_CLIENT_SIDE_SSL */
191 *keys
= lkeys
= psMalloc(pool
, sizeof(sslKeys_t
));
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
);
202 matrixRsaFreeKeys(lkeys
);
206 The first cert in certFile must be associated with the provided
210 rc
= matrixX509ReadPrivKey(pool
, privFile
, privPass
, &privKeyMem
,
213 matrixStrDebugMsg("Error reading private key file: %s\n",
215 matrixRsaFreeKeys(lkeys
);
218 rc
= matrixRsaParsePrivKey(pool
, privKeyMem
, privKeyMemLen
,
219 &lkeys
->cert
.privKey
);
221 matrixStrDebugMsg("Error parsing private key file: %s\n",
224 matrixRsaFreeKeys(lkeys
);
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
);
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
];
259 lkeys
->caCerts
= currCert
;
261 prevCert
->next
= currCert
;
266 caStream
+= chain
[i
]; caCertLen
-= chain
[i
];
269 sslAssert(caCertLen
== 0);
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
);
282 #endif /* USE_CLIENT_SIDE_SSL */
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
++) {
308 *outLen
= certChainLen
= i
= 0;
312 For PKI product purposes, this routine now accepts a chain of certs.
314 if (fileName
!= NULL
) {
315 fileName
+= parseList(pool
, fileName
, sep
, &certFile
);
320 while (certFile
!= NULL
) {
322 if (i
== MAX_CHAIN_LENGTH
) {
323 matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
329 if ((rc
= psGetFileBin(pool
, certFile
, (unsigned char**)&certBuf
,
331 matrixStrDebugMsg("Couldn't open file %s\n", 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'
355 oneCert
[i
] = psMalloc(pool
, (*chain
)[i
]);
356 certBufLen
-= (int32
)(end
- certBuf
);
358 memset(oneCert
[i
], '\0', (*chain
)[i
]);
360 if (ps_base64_decode((unsigned char*)start
, (*chain
)[i
], oneCert
[i
],
361 &(*chain
)[i
]) != 0) {
363 matrixStrDebugMsg("Unable to base64 decode certificate\n", NULL
);
367 certChainLen
+= (*chain
)[i
];
369 if (i
== MAX_CHAIN_LENGTH
) {
370 matrixIntDebugMsg("Exceeded maximum cert chain length of %d\n",
381 fileName
+= parseList(pool
, fileName
, sep
, &certFile
);
384 *outLen
= certChainLen
;
386 Don't bother stringing them together if only one was passed in
389 sslAssert(certChainLen
== (*chain
)[0]);
393 *out
= tmp
= psMalloc(pool
, certChainLen
);
394 for (i
=0; i
< MAX_CHAIN_LENGTH
; i
++) {
396 memcpy(tmp
, oneCert
[i
], (*chain
)[i
]);
404 for (i
=0; i
< MAX_CHAIN_LENGTH
; i
++) {
405 if (oneCert
[i
]) psFree(oneCert
[i
]);
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
,
419 unsigned char *certBuf
;
424 if (matrixX509ReadCert(pool
, certFile
, &certBuf
, &certBufLen
, &chain
) < 0) {
425 matrixStrDebugMsg("Unable to read certificate file %s\n",
427 if (certBuf
) psFree(certBuf
);
430 if (matrixX509ParsePubKey(pool
, certBuf
, certBufLen
, key
) < 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
;
454 if (certFiles
== NULL
) {
458 if (matrixX509ReadCert(pool
, certFiles
, &certBin
, &certLen
, &chain
) < 0) {
459 matrixStrDebugMsg("Error reading cert file %s\n", (char*)certFiles
);
463 The first cert is allocated in the keys struct. All others in
464 linked list are allocated here.
468 while (chain
[i
] != 0) {
472 currCert
->next
= psMalloc(pool
, sizeof(sslLocalCert_t
));
473 if (currCert
->next
== NULL
) {
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
];
487 sslAssert(certLen
== 0);
491 /******************************************************************************/
495 static int32
parseList(psPool_t
*pool
, const char *list
, const char *sep
,
498 int32 start
, listLen
;
501 start
= listLen
= (int32
)strlen(list
) + 1;
506 tmp
= *item
= psMalloc(pool
, listLen
);
508 return -8; /* SSL_MEM_ERROR */
510 memset(*item
, 0, listLen
);
511 while (listLen
> 0) {
512 if (*list
== sep
[0]) {
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
)
542 sslLocalCert_t
*current
, *next
;
543 unsigned char *binPtr
;
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
));
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
560 current
= &lkeys
->cert
;
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
);
574 Account for the overhead of storing the length itself
576 lenOh
= (int32
)(certBuf
- binPtr
);
580 First cert is already malloced
583 next
= psMalloc(pool
, sizeof(sslLocalCert_t
));
584 memset(next
, 0x0, sizeof(sslLocalCert_t
));
585 current
->next
= next
;
588 current
->certBin
= psMalloc(pool
, len
);
589 memcpy(current
->certBin
, certBuf
, len
);
590 current
->certLen
= len
;
601 if (matrixRsaParsePrivKey(pool
, privBuf
, privLen
,
602 &lkeys
->cert
.privKey
) < 0) {
603 matrixStrDebugMsg("Error reading private key mem\n", NULL
);
604 matrixRsaFreeKeys(lkeys
);
613 #ifdef USE_CLIENT_SIDE_SSL
614 if (trustedCABuf
!= NULL
&& trustedCALen
> 0) {
616 binPtr
= trustedCABuf
;
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",
626 matrixRsaFreeKeys(lkeys
);
630 Account for the overhead of storing the length itself
632 lenOh
= (int32
)(trustedCABuf
- binPtr
);
634 trustedCABuf
-= lenOh
;
636 if (matrixX509ParseCert(pool
, trustedCABuf
, len
, ¤tCA
) < 0) {
637 matrixX509FreeCert(currentCA
);
638 matrixStrDebugMsg("Error parsing CA cert\n", NULL
);
639 matrixRsaFreeKeys(lkeys
);
643 First cert should be assigned to lkeys
646 lkeys
->caCerts
= currentCA
;
647 nextCA
= lkeys
->caCerts
;
649 nextCA
->next
= currentCA
;
652 currentCA
= currentCA
->next
;
655 binPtr
= trustedCABuf
;
659 #endif /* USE_CLIENT_SIDE_SSL */
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
)
675 sslCert_t
*certStruct
;
678 if (matrixX509ParseCert(pool
, certBuf
, certLen
, &certStruct
) < 0) {
679 matrixX509FreeCert(certStruct
);
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
);
691 mp_copy(&certStruct
->publicKey
.e
, &lkey
->e
);
692 mp_copy(&certStruct
->publicKey
.N
, &lkey
->N
);
697 lkey
->size
= certStruct
->publicKey
.size
;
699 matrixX509FreeCert(certStruct
);
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
,
714 sslMd5Context_t md5Ctx
;
715 sslSha1Context_t sha1Ctx
;
716 unsigned char *p
, *end
, *certStart
, *certEnd
;
717 int32 certLen
, len
, parsing
;
719 sslMd2Context_t md2Ctx
;
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
));
730 return -8; /* SSL_MEM_ERROR */
732 memset(cert
, '\0', sizeof(sslCert_t
));
737 Certificate ::= SEQUENCE {
738 tbsCertificate TBSCertificate,
739 signatureAlgorithm AlgorithmIdentifier,
740 signatureValue BIT STRING }
744 if (getSequence(&p
, (int32
)(end
- p
), &len
) < 0) {
745 matrixStrDebugMsg("Initial cert parse error\n", NULL
);
750 TBSCertificate ::= SEQUENCE {
751 version [0] EXPLICIT Version DEFAULT v1,
752 serialNumber CertificateSerialNumber,
753 signature AlgorithmIdentifier,
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
);
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
);
779 if (cert
->version
!= 2) {
780 matrixIntDebugMsg("Warning: non-v3 certificate version: %d\n",
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
);
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) {
804 RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
806 RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
808 AttributeTypeAndValue ::= SEQUENCE {
810 value AttributeValue }
812 AttributeType ::= OBJECT IDENTIFIER
814 AttributeValue ::= ANY DEFINED BY AttributeType
816 if (getDNAttributes(pool
, &p
, (int32
)(end
- p
), &cert
->issuer
) < 0) {
820 Validity ::= SEQUENCE {
824 if (getValidity(pool
, &p
, (int32
)(end
- p
), &cert
->notBefore
,
825 &cert
->notAfter
) < 0) {
831 if (getDNAttributes(pool
, &p
, (int32
)(end
- p
), &cert
->subject
) < 0) {
835 SubjectPublicKeyInfo ::= SEQUENCE {
836 algorithm AlgorithmIdentifier,
837 subjectPublicKey BIT STRING }
839 if (getSequence(&p
, (int32
)(end
- p
), &len
) < 0) {
842 if (getAlgorithmIdentifier(&p
, (int32
)(end
- p
),
843 &cert
->pubKeyAlgorithm
, 1) < 0) {
847 if (getPubKey(pool
, &p
, (int32
)(end
- p
), &cert
->publicKey
) < 0) {
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
);
870 This is the end of the cert. Do a check here to be certain
876 Certificate signature info
878 if (getAlgorithmIdentifier(&p
, (int32
)(end
- p
),
879 &cert
->sigAlgorithm
, 0) < 0) {
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
);
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
);
902 else if (cert
->certAlgorithm
== OID_RSA_MD2
) {
903 matrixMd2Init(&md2Ctx
);
904 matrixMd2Update(&md2Ctx
, certStart
, certLen
);
905 matrixMd2Final(&md2Ctx
, cert
->sigHash
);
909 if (getSignature(pool
, &p
, (int32
)(end
- p
), &cert
->signature
,
910 &cert
->signatureLen
) < 0) {
914 The ability to parse additional chained certs is a PKI product
915 feature addition. Chaining in MatrixSSL is handled internally.
918 cert
->next
= psMalloc(pool
, sizeof(sslCert_t
));
920 memset(cert
, '\0', sizeof(sslCert_t
));
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
;
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
) {
956 psFree(active
->data
);
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 */
988 /******************************************************************************/
990 Do the signature validation for a subject certificate against a
993 int32
psAsnConfirmSignature(unsigned char *sigHash
, unsigned char *sigOut
,
996 unsigned char *end
, *p
= sigOut
;
997 unsigned char hash
[SSL_SHA1_HASH_SIZE
];
1002 DigestInfo ::= SEQUENCE {
1003 digestAlgorithm DigestAlgorithmIdentifier,
1006 DigestAlgorithmIdentifier ::= AlgorithmIdentifier
1008 Digest ::= OCTET STRING
1010 if (getSequence(&p
, (int32
)(end
- p
), &len
) < 0) {
1015 Could be MD5 or SHA1
1017 if (getAlgorithmIdentifier(&p
, (int32
)(end
- p
), &oi
, 0) < 0) {
1020 if ((*p
++ != ASN_OCTET_STRING
) ||
1021 asnParseLength(&p
, (int32
)(end
- p
), &len
) < 0 || (end
- p
) < len
) {
1024 memcpy(hash
, p
, len
);
1025 if (oi
== OID_MD5
|| oi
== OID_MD2
) {
1026 if (len
!= SSL_MD5_HASH_SIZE
) {
1029 } else if (oi
== OID_SHA1
) {
1030 if (len
!= SSL_SHA1_HASH_SIZE
) {
1037 hash should match sigHash
1039 if (memcmp(hash
, sigHash
, len
) != 0) {
1045 /******************************************************************************/
1049 static int32
lookupExt(unsigned char md5hash
[SSL_MD5_HASH_SIZE
])
1052 const unsigned char *tmp
;
1055 if (extTable
[i
].id
== -1) {
1058 tmp
= extTable
[i
].hash
;
1059 for (j
= 0; j
< SSL_MD5_HASH_SIZE
; j
++) {
1060 if (md5hash
[j
] != tmp
[j
]) {
1063 if (j
== SSL_MD5_HASH_SIZE
- 1) {
1064 return extTable
[i
].id
;
1070 /******************************************************************************/
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
;
1090 Not treating this as an error because it is optional.
1092 if (*p
!= (ASN_CONTEXT_SPECIFIC
| ASN_CONSTRUCTED
| expVal
)) {
1096 if (asnParseLength(&p
, (int32
)(end
- p
), &len
) < 0 || (end
- p
) < len
) {
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) {
1110 while ((p
!= extEnd
) && *p
== (ASN_SEQUENCE
| ASN_CONSTRUCTED
)) {
1111 if (getSequence(&p
, (int32
)(extEnd
- p
), &fullExtLen
) < 0) {
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
) {
1129 if (asnParseLength(&p
, (int32
)(extEnd
- p
), &len
) < 0 ||
1130 (extEnd
- p
) < len
) {
1134 Send the OID through a digest to get the unique id
1136 matrixMd5Init(&md5ctx
);
1138 matrixMd5Update(&md5ctx
, p
, sizeof(char));
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
1149 if (*p
== ASN_BOOLEAN
) {
1152 matrixStrDebugMsg("Error parsing cert extension\n", NULL
);
1159 if (extEnd
- p
< 1 || (*p
++ != ASN_OCTET_STRING
) ||
1160 asnParseLength(&p
, (int32
)(extEnd
- p
), &len
) < 0 ||
1162 matrixStrDebugMsg("Expecting OCTET STRING in ext parse\n", NULL
);
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) {
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
1188 Have seen some certs that don't include a cA bool.
1190 if (*p
== ASN_BOOLEAN
) {
1195 extensions
->bc
.ca
= *p
++;
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
1204 if (*p
== ASN_INTEGER
) {
1205 if (getInteger(&p
, (int32
)(extEnd
- p
),
1206 &(extensions
->bc
.pathLenConstraint
)) < 0) {
1210 extensions
->bc
.pathLenConstraint
= -1;
1213 case EXT_ALT_SUBJECT_NAME
:
1214 if (getSequence(&p
, (int32
)(extEnd
- p
), &len
) < 0) {
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 }
1234 if (extensions
->san
== NULL
) {
1235 activeName
= extensions
->san
= psMalloc(pool
,
1236 sizeof(sslSubjectAltName_t
));
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
) {
1258 memcpy(activeName
->name
, "other", 5);
1261 memcpy(activeName
->name
, "email", 5);
1264 memcpy(activeName
->name
, "DNS", 3);
1267 memcpy(activeName
->name
, "x400Address", 11);
1270 memcpy(activeName
->name
, "directoryName", 13);
1273 memcpy(activeName
->name
, "ediPartyName", 12);
1276 memcpy(activeName
->name
, "URI", 3);
1279 memcpy(activeName
->name
, "iPAddress", 9);
1282 memcpy(activeName
->name
, "registeredID", 12);
1285 memcpy(activeName
->name
, "unknown", 7);
1290 activeName
->dataLen
= *p
++;
1291 if (extEnd
- p
< activeName
->dataLen
) {
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;
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) {
1320 Have seen a cert that has a zero length ext here. Let it pass.
1326 All memebers are optional
1328 if (*p
== (ASN_CONTEXT_SPECIFIC
| ASN_PRIMITIVE
| 0)) {
1330 if (asnParseLength(&p
, (int32
)(extEnd
- p
),
1331 &extensions
->ak
.keyLen
) < 0 ||
1332 extEnd
- p
< extensions
->ak
.keyLen
) {
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)) {
1344 if (asnParseLength(&p
, (int32
)(extEnd
- p
), &len
) < 0 ||
1345 len
< 1 || extEnd
- p
< len
) {
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
);
1358 if (asnParseLength(&p
, (int32
)(extEnd
- p
), &len
) < 0 ||
1362 if (getDNAttributes(pool
, &p
, (int32
)(extEnd
- p
),
1363 &(extensions
->ak
.attribs
)) < 0) {
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) {
1376 extensions
->ak
.serialNumLen
= len
;
1382 KeyUsage ::= BIT STRING {
1383 digitalSignature (0),
1385 keyEncipherment (2),
1386 dataEncipherment (3),
1394 if (*p
++ != ASN_BIT_STRING
) {
1397 if (asnParseLength(&p
, (int32
)(extEnd
- p
), &len
) < 0 ||
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
;
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
1420 if (*p
++ != ASN_OCTET_STRING
|| asnParseLength(&p
,
1421 (int32
)(extEnd
- p
), &(extensions
->sk
.len
)) < 0 ||
1422 extEnd
- p
< extensions
->sk
.len
) {
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
;
1432 #endif /* USE_FULL_CERT_PARSE */
1434 Unsupported or skipping because USE_FULL_CERT_PARSE is undefined
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",
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
));
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
)
1474 *subjectCert
= chain
;
1476 while ((*subjectCert
)->next
!= NULL
) {
1477 ic
= (*subjectCert
)->next
;
1478 if (matrixX509ValidateCertInternal(pool
, *subjectCert
, ic
, 1) < 0) {
1483 If any portion is invalid, it's all invalid
1485 if ((*subjectCert
)->valid
!= 1) {
1488 *subjectCert
= (*subjectCert
)->next
;
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) {
1506 *valid
= subjectCert
->valid
;
1510 static int32
matrixX509ValidateCertInternal(psPool_t
*pool
,
1511 sslCert_t
*subjectCert
, sslCert_t
*issuerCert
, int32 chain
)
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
);
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.
1535 if (subjectCert
!= ic
) {
1537 Certificate authority constraint only available in version 3 certs
1539 if ((ic
->version
> 1) && (ic
->extensions
.bc
.ca
<= 0)) {
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) {
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
) {
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 */
1573 matrixStrDebugMsg("Unsupported signature algorithm\n", NULL
);
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
,
1584 matrixStrDebugMsg("Unable to RSA decrypt signature\n", NULL
);
1585 if (issuerCert
) return -1;
1588 rc
= psAsnConfirmSignature(subjectCert
->sigHash
, sigOut
, sigLen
);
1592 If this is a chain test, fail on any gaps in the chain
1602 Fall through to here only if passed signature check.
1604 subjectCert
->valid
= 1;
1610 /******************************************************************************/
1612 Calls a user defined callback to allow for manual validation of the
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
;
1621 if (certValidator
== NULL
) {
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
));
1671 return -8; /* SSL_MEM_ERROR */
1673 memset(next
, 0x0, sizeof(sslCertInfo_t
));
1674 current
->next
= next
;
1677 subjectCert
= subjectCert
->next
;
1682 rc
= certValidator(cert
, arg
);
1693 #endif /* USE_X509 */
1694 #endif /* USE_RSA */
1697 /******************************************************************************/