File Coverage

inc/matrixssl-3-9-3-open/crypto/keyformat/crl.c
Criterion Covered Total %
statement 30 370 8.1
branch 10 260 3.8
condition n/a
subroutine n/a
pod n/a
total 40 630 6.3


line stmt bran cond sub pod time code
1             /**
2             * @file crl.c
3             * @version 950bba4 (HEAD -> master)
4             *
5             * Certificate Revocation List tools
6             */
7             /*
8             * Copyright (c) 2013-2017 INSIDE Secure Corporation
9             * All Rights Reserved
10             *
11             * The latest version of this code is available at http://www.matrixssl.org
12             *
13             * This software is open source; you can redistribute it and/or modify
14             * it under the terms of the GNU General Public License as published by
15             * the Free Software Foundation; either version 2 of the License, or
16             * (at your option) any later version.
17             *
18             * This General Public License does NOT permit incorporating this software
19             * into proprietary programs. If you are unable to comply with the GPL, a
20             * commercial license for this software may be purchased from INSIDE at
21             * http://www.insidesecure.com/
22             *
23             * This program is distributed in WITHOUT ANY WARRANTY; without even the
24             * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25             * See the GNU General Public License for more details.
26             *
27             * You should have received a copy of the GNU General Public License
28             * along with this program; if not, write to the Free Software
29             * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30             * http://www.gnu.org/copyleft/gpl.html
31             */
32             /******************************************************************************/
33              
34             #include "../cryptoImpl.h"
35              
36             #ifdef USE_CRL
37             # ifdef USE_CERT_PARSE
38              
39             # ifdef USE_MULTITHREADING
40             static psMutex_t g_crlTableLock;
41             # endif
42              
43             /* Seems like many CRLs are not adhering to the specification that this
44             extension be present. That just leaves us with the DN to match against
45             if we disable this define. Not a big concern to disable it because the
46             authentication is either going to pass or fail based on sig validation */
47             /* #define ENFORCE_CRL_AUTH_KEY_ID_EXT */
48              
49             static void internalFreeCRL(psX509Crl_t *crl);
50              
51             /* The global CRL cache is a linked list of psX509Crl_t structures. A
52             psX509Crl_t structure represents a single CRL file */
53             static psX509Crl_t *g_CRL = NULL;
54              
55              
56             /* Invoked from psCryptoOpen */
57 17           int32_t psCrlOpen()
58             {
59             # ifdef USE_MULTITHREADING
60             psCreateMutex(&g_crlTableLock, 0);
61             # endif
62 17           return PS_SUCCESS;
63             }
64              
65             /* Invoked from psCryptoClose */
66 14           void psCrlClose()
67             {
68 14           psCRL_DeleteAll();
69             # ifdef USE_MULTITHREADING
70             psDestroyMutex(&g_crlTableLock);
71             # endif
72 14           }
73              
74             /* Helper for CRL insert */
75 0           static int internalCRLInsert(psX509Crl_t *crl)
76             {
77             psX509Crl_t *next;
78              
79 0 0         if (crl == NULL)
80             {
81 0           return 0;
82             }
83              
84 0 0         if (g_CRL == NULL)
85             {
86             /* first one */
87 0           g_CRL = crl;
88 0           return 1;
89             }
90             /* append */
91 0           next = g_CRL;
92 0 0         if (g_CRL == crl)
93             {
94 0           return 0; /* no pointer dups */
95             }
96 0 0         while (next->next)
97             {
98 0           next = next->next;
99 0 0         if (next == crl) /* no pointer dups */
100             {
101 0           return 0;
102             }
103             }
104 0           next->next = crl;
105 0           return 1;
106             }
107              
108             /* Blindly append a CRL to the g_CRL list. Consider psCRL_Update instead.
109             1 - Added, 0 - Didn't */
110 0           int psCRL_Insert(psX509Crl_t *crl)
111             {
112             int rc;
113              
114             # ifdef USE_MULTITHREADING
115             psLockMutex(&g_crlTableLock);
116             # endif /* USE_MULTITHREADING */
117              
118 0           rc = internalCRLInsert(crl);
119              
120             # ifdef USE_MULTITHREADING
121             psUnlockMutex(&g_crlTableLock);
122             # endif /* USE_MULTITHREADING */
123 0           return rc;
124             }
125              
126             /* Helper for Remove and Delete to take a CRL out of g_CRL */
127 0           static int internalShrinkCRLtable(psX509Crl_t *crl, int delete)
128             {
129             psX509Crl_t *prev, *curr, *next;
130              
131             /* Return whether or not it was found in the list to help with the
132             standalone psX509FreeCRL call logic */
133              
134 0 0         if (g_CRL == NULL || crl == NULL)
    0          
135             {
136 0           return 0;
137             }
138 0           prev = NULL;
139 0           curr = g_CRL;
140 0           next = curr->next;
141 0 0         while (curr)
142             {
143 0 0         if (curr == crl)
144             {
145 0 0         if (delete)
146             {
147 0           internalFreeCRL(crl);
148             }
149             else
150             {
151 0           curr->next = NULL;
152             }
153 0 0         if (prev == NULL && next == NULL)
    0          
154             {
155             /* Only one in list */
156 0           g_CRL = NULL;
157             }
158 0 0         else if (prev == NULL && next != NULL)
    0          
159             {
160             /* Removed first one in list */
161 0           g_CRL = next;
162             }
163 0 0         else if (prev != NULL)
164             {
165             /* Removed middle or end */
166 0           prev->next = next;
167             }
168 0           return 1;
169             }
170 0           prev = curr;
171 0           curr = curr->next;
172 0 0         if (curr)
173             {
174             /* curr can be NULL if we never found crl */
175 0           next = curr->next;
176             }
177             }
178 0           return 0;
179             }
180              
181             /* Remove a CRL from g_CRL but don't free the associated CRL */
182 0           int psCRL_Remove(psX509Crl_t *crl)
183             {
184             int rc;
185              
186             # ifdef USE_MULTITHREADING
187             psLockMutex(&g_crlTableLock);
188             # endif /* USE_MULTITHREADING */
189              
190 0           rc = internalShrinkCRLtable(crl, 0);
191              
192             # ifdef USE_MULTITHREADING
193             psUnlockMutex(&g_crlTableLock);
194             # endif /* USE_MULTITHREADING */
195              
196 0           return rc;
197             }
198              
199             /* Remove a CRL from g_CRL and free the associated CRL */
200 0           int psCRL_Delete(psX509Crl_t *crl)
201             {
202             int rc;
203              
204             # ifdef USE_MULTITHREADING
205             psLockMutex(&g_crlTableLock);
206             # endif /* USE_MULTITHREADING */
207              
208 0           rc = internalShrinkCRLtable(crl, 1);
209              
210             # ifdef USE_MULTITHREADING
211             psUnlockMutex(&g_crlTableLock);
212             # endif /* USE_MULTITHREADING */
213 0           return rc;
214             }
215              
216             /* Remove all CRLs from g_CRL but don't free the associated memory. Assumes
217             the user will be using psX509FreeCRL later */
218 0           void psCRL_RemoveAll()
219             {
220             psX509Crl_t *curr, *next;
221              
222             # ifdef USE_MULTITHREADING
223             psLockMutex(&g_crlTableLock);
224             # endif /* USE_MULTITHREADING */
225 0           curr = g_CRL;
226 0           next = curr->next;
227 0 0         while (next)
228             {
229 0           next = curr->next;
230 0           curr->next = NULL;
231 0           curr = next;
232             }
233 0           g_CRL = NULL;
234             # ifdef USE_MULTITHREADING
235             psUnlockMutex(&g_crlTableLock);
236             # endif /* USE_MULTITHREADING */
237 0           }
238              
239             /* Remove all CRLs from g_CRL and free the associated memory */
240 14           void psCRL_DeleteAll()
241             {
242             psX509Crl_t *curr, *next;
243              
244             # ifdef USE_MULTITHREADING
245             psLockMutex(&g_crlTableLock);
246             # endif /* USE_MULTITHREADING */
247              
248 14           curr = g_CRL;
249 14 50         while (curr)
250             {
251 0           next = curr->next;
252 0           internalShrinkCRLtable(curr, 1);
253 0           curr = next;
254             }
255 14 50         psAssert(g_CRL == NULL);
256             # ifdef USE_MULTITHREADING
257             psUnlockMutex(&g_crlTableLock);
258             # endif /* USE_MULTITHREADING */
259 14           }
260              
261             /* Helpers to see if the two CRLs are from the same issuer */
262 0           int32 internalCRLmatch(psX509Crl_t *existing, psX509Crl_t *new)
263             {
264             /* Same DN? */
265 0 0         if (memcmpct(existing->issuer.hash, new->issuer.hash, SHA1_HASH_SIZE) != 0)
266             {
267 0           return -1;
268             }
269             # ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT
270             /* Same AuthKeyId? */
271             if (existing->extensions.ak.keyId == NULL ||
272             new->extensions.ak.keyId == NULL)
273             {
274             /* Should never be possible */
275             return PS_PARSE_FAIL;
276             }
277             if (existing->extensions.ak.keyLen != new->extensions.ak.keyLen)
278             {
279             return -1;
280             }
281             if (memcmpct(existing->extensions.ak.keyId, new->extensions.ak.keyId,
282             new->extensions.ak.keyLen) != 0)
283             {
284             return -1;
285             }
286             # endif
287             /* Looks like a match */
288 0           return PS_TRUE;
289             }
290              
291             /* Remove existing CRL if it exists. Append this one.
292             FUTURE: Support Delta CRL */
293 0           int psCRL_Update(psX509Crl_t *crl, int deleteExisting)
294             {
295             psX509Crl_t *curr, *next;
296             int rc;
297              
298 0 0         if (crl == NULL)
299             {
300 0           return 0;
301             }
302             # ifdef USE_MULTITHREADING
303             psLockMutex(&g_crlTableLock);
304             # endif /* USE_MULTITHREADING */
305             /* Currently no Delta CRL support so replace the CRL if we find the
306             same issuer. Add otherwise. */
307 0           curr = g_CRL;
308 0 0         while (curr)
309             {
310 0           next = curr->next;
311 0 0         if (internalCRLmatch(curr, crl) == PS_TRUE)
312             {
313             /* Just do a check to make sure the user isn't trying to update
314             with the exact same CRL pointer */
315 0 0         if (curr == crl)
316             {
317             # ifdef USE_MULTITHREADING
318             psUnlockMutex(&g_crlTableLock);
319             # endif /* USE_MULTITHREADING */
320 0           return 0;
321             }
322 0           internalShrinkCRLtable(curr, deleteExisting);
323 0           break;
324             }
325 0           curr = next;
326             }
327 0           rc = internalCRLInsert(crl);
328             # ifdef USE_MULTITHREADING
329             psUnlockMutex(&g_crlTableLock);
330             # endif /* USE_MULTITHREADING */
331 0           return rc;
332             }
333              
334             /* Helper to see if we have a matching CRL for the given subject cert. So
335             this means we are looking at the issuer/authority fields of the cert */
336 0           static int32 internalMatchSubject(psX509Cert_t *cert, psX509Crl_t *CRL)
337             {
338             /* Same DN? */
339 0 0         if (memcmpct(CRL->issuer.hash, cert->issuer.hash, SHA1_HASH_SIZE) != 0)
340             {
341 0           return PS_CERT_AUTH_FAIL_DN;
342             }
343             # ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT
344             /* Same AuthKeyId? */
345             if (CRL->extensions.ak.keyId == NULL)
346             {
347             return PS_CERT_AUTH_FAIL_EXTENSION;
348             }
349             if (cert->extensions.ak.keyId == NULL)
350             {
351             return PS_CERT_AUTH_FAIL_EXTENSION;
352             }
353             if (CRL->extensions.ak.keyLen != cert->extensions.ak.keyLen)
354             {
355             return PS_CERT_AUTH_FAIL_EXTENSION;
356             }
357             if (memcmpct(CRL->extensions.ak.keyId, cert->extensions.ak.keyId,
358             CRL->extensions.ak.keyLen) != 0)
359             {
360             return PS_CERT_AUTH_FAIL_EXTENSION;
361             }
362             # endif
363             /* Looks good */
364 0           return 1;
365             }
366              
367             /* Check if nextUpdate time appears correct. Returns -1 when
368             timestamp was unparseable or the CRL was expired. 0 for success. */
369 0           static int32_t nextUpdateTest(const char *c, int32 timeType)
370             {
371             int32 err;
372             psBrokenDownTime_t timeNow;
373             psBrokenDownTime_t nextTime;
374             psBrokenDownTime_t nextTimeLinger;
375              
376 0           err = psGetBrokenDownGMTime(&timeNow, 0);
377 0 0         if (err != PS_SUCCESS)
378             {
379 0           return -1;
380             }
381              
382 0 0         err = psBrokenDownTimeImport(
383             &nextTime, c, strlen(c),
384             timeType == ASN_UTCTIME ?
385             PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0);
386 0 0         if (err != PS_SUCCESS)
387             {
388 0           return -1;
389             }
390              
391 0           memcpy(&nextTimeLinger, &nextTime, sizeof nextTimeLinger);
392 0           err = psBrokenDownTimeAdd(&nextTimeLinger, PS_CRL_TIME_LINGER);
393 0 0         if (err != PS_SUCCESS)
394             {
395 0           return -1;
396             }
397              
398 0 0         if (psBrokenDownTimeCmp(&timeNow, &nextTimeLinger) > 0)
399             {
400             /* nextTime is in past. */
401 0           return -1;
402             }
403 0           return 0;
404             }
405              
406 1150           static psX509Crl_t *internalGetCrlForCert(psX509Cert_t *cert)
407             {
408             psX509Crl_t *curr;
409              
410 1150 50         if (cert == NULL)
411             {
412 0           return NULL;
413             }
414 1150           curr = g_CRL;
415 1150 50         while (curr)
416             {
417 0 0         if (internalMatchSubject(cert, curr) == PS_TRUE)
418             {
419             /* This is the point where we want to make sure this CRL isn't
420             expired. We do this by looking at the nextUpdate time and
421             seeing if we are beyond that */
422 0 0         if (nextUpdateTest(curr->nextUpdate, curr->nextUpdateType) < 0)
423             {
424             /* Got it, but it's expired */
425 0           curr->expired = 1;
426             }
427 0           return curr;
428             }
429 0           curr = curr->next;
430             }
431 1150           return NULL;
432             }
433              
434             /* Given a cert, do we have a CRL match for the issuer?
435             Return if so or NULL if not */
436 0           psX509Crl_t *psCRL_GetCRLForCert(psX509Cert_t *cert)
437             {
438 0           psX509Crl_t *rc = NULL;
439              
440             # ifdef USE_MULTITHREADING
441             psLockMutex(&g_crlTableLock);
442             # endif /* USE_MULTITHREADING */
443              
444 0           rc = internalGetCrlForCert(cert);
445              
446             # ifdef USE_MULTITHREADING
447             psUnlockMutex(&g_crlTableLock);
448             # endif /* USE_MULTITHREADING */
449 0           return rc;
450             }
451              
452              
453             /*
454             -1 no entry in the cache for this cert at all
455             0 entry is found and cert is NOT revoked
456             1 entry is found and cert IS revoked
457              
458             A CRL may be passed in if that specific one is being tested. Otherwise
459             pass NULL to search the g_CRL
460             */
461 0           int32_t internalCrlIsRevoked(psX509Cert_t *cert, psX509Crl_t *CRL,
462             psBrokenDownTime_t *bdt)
463             {
464             psX509Crl_t *crl;
465             x509revoked_t *entry;
466              
467 0 0         if (cert == NULL)
468             {
469 0           return -1;
470             }
471              
472 0 0         if (CRL)
473             {
474 0           crl = CRL;
475             }
476             else
477             {
478 0 0         if ((crl = internalGetCrlForCert(cert)) == NULL)
479             {
480 0           return -1;
481             }
482             }
483 0 0         if (crl->revoked == NULL)
484             {
485             /* It is totally reasonable to have a CRL with no revoked certs */
486 0           return 0;
487             }
488 0 0         for (entry = crl->revoked; entry != NULL; entry = entry->next)
489             {
490 0 0         if (cert->serialNumberLen == entry->serialLen)
491             {
492 0 0         if (memcmpct(cert->serialNumber, entry->serial, entry->serialLen)
493             == 0)
494             {
495 0 0         if (bdt)
496             {
497 0           memcpy(bdt, &entry->revocationDateBDT,
498             sizeof(psBrokenDownTime_t));
499             }
500 0           return 1; /* REVOKED! */
501             }
502             }
503             }
504 0           return 0; /* never found it. good to go */
505             }
506              
507             /*
508             Not sure this needs to be public. The "determine" API is actually
509             doing the full check
510              
511             -1 no entry in the cache for this cert at all
512             0 entry is found and cert is NOT revoked
513             1 entry is found and cert IS revoked
514              
515             A CRL may be passed in if that specific one is being tested. Otherwise
516             pass NULL to search the g_CRL
517             */
518 0           int32_t psCRL_isRevoked(psX509Cert_t *cert, psX509Crl_t *CRL)
519             {
520             int32_t rc;
521              
522             # ifdef USE_MULTITHREADING
523             psLockMutex(&g_crlTableLock);
524             # endif /* USE_MULTITHREADING */
525              
526 0           rc = internalCrlIsRevoked(cert, CRL, NULL);
527              
528             # ifdef USE_MULTITHREADING
529             psUnlockMutex(&g_crlTableLock);
530             # endif /* USE_MULTITHREADING */
531              
532 0           return rc;
533             }
534              
535 1150           static int doesCertExpectCRL(psX509Cert_t *cert)
536             {
537 1150 100         if (cert->extensions.crlDist)
538             {
539 2           return PS_TRUE;
540             }
541 1148           return PS_FALSE;
542             }
543              
544             /*
545             Uses the psCRL_ format to highlight the use of g_CRL cache
546              
547             Updates the "revokedStatus" member of a psX509Cert_t based on information
548             from within the cert itself and on the revocation status if a g_CRL entry
549             is found.
550             */
551 1150           int32_t psCRL_determineRevokedStatusBDT(psX509Cert_t *cert,
552             psBrokenDownTime_t *bdt)
553             {
554             psX509Crl_t *crl;
555             int expectCrl;
556             int32_t revoked;
557              
558 1150 50         if (cert == NULL)
559             {
560 0           return 0;
561             }
562             # ifdef USE_MULTITHREADING
563             psLockMutex(&g_crlTableLock);
564             # endif /* USE_MULTITHREADING */
565              
566 1150           crl = internalGetCrlForCert(cert);
567              
568 1150 50         if (crl)
569             {
570             /* Not going to move along if the CRL has expired */
571 0 0         if (crl->expired)
572             {
573 0           cert->revokedStatus = CRL_CHECK_CRL_EXPIRED;
574             # ifdef USE_MULTITHREADING
575             psUnlockMutex(&g_crlTableLock);
576             # endif /* USE_MULTITHREADING */
577 0           return cert->revokedStatus;
578             }
579              
580             /* If we now have a CRL that is not authenticated yet, let's see if
581             if our subject happens to have a parent that we can try against.
582             This case happens if a CRL for an child certificate was
583             fetched out-of-handshake and now a reconnection attempt is being
584             made. We now have the parent for that child cert and can
585             attempt to authenticate */
586 0 0         if (crl->authenticated == 0 && cert->next)
    0          
587             {
588 0           psX509AuthenticateCRL(cert->next, crl, NULL);
589             }
590              
591             /* test it and set the status */
592 0           revoked = internalCrlIsRevoked(cert, crl, bdt);
593 0 0         if (revoked == 0 && crl->authenticated == 1)
    0          
594             {
595 0           cert->revokedStatus = CRL_CHECK_PASSED_AND_AUTHENTICATED;
596              
597             }
598 0 0         else if (revoked == 0 && crl->authenticated == 0)
    0          
599             {
600 0           cert->revokedStatus = CRL_CHECK_PASSED_BUT_NOT_AUTHENTICATED;
601              
602             }
603 0 0         else if (revoked == 1 && crl->authenticated == 1)
    0          
604             {
605 0           cert->revokedStatus = CRL_CHECK_REVOKED_AND_AUTHENTICATED;
606              
607             }
608 0 0         else if (revoked == 1 && crl->authenticated == 0)
    0          
609             {
610 0           cert->revokedStatus = CRL_CHECK_REVOKED_BUT_NOT_AUTHENTICATED;
611              
612             }
613             else
614             {
615             psTraceCrypto("Unexpected revoked/authenticated combo\n");
616             }
617             }
618             else
619             {
620 1150           expectCrl = doesCertExpectCRL(cert);
621 1150 100         if (expectCrl)
622             {
623 2           cert->revokedStatus = CRL_CHECK_EXPECTED; /* but no entry */
624             }
625             else
626             {
627 1148           cert->revokedStatus = CRL_CHECK_NOT_EXPECTED;
628             }
629             }
630             # ifdef USE_MULTITHREADING
631             psUnlockMutex(&g_crlTableLock);
632             # endif /* USE_MULTITHREADING */
633 1150           return cert->revokedStatus;
634             }
635              
636 1150           int32_t psCRL_determineRevokedStatus(psX509Cert_t *cert)
637             {
638 1150           return psCRL_determineRevokedStatusBDT(cert, NULL);
639             }
640              
641             /********************* end of psCRL_ family of APIs ***************************/
642              
643              
644             /******************************************************************************/
645 0           static void x509FreeRevoked(x509revoked_t **revoked, psPool_t *pool)
646             {
647 0           x509revoked_t *next, *curr = *revoked;
648              
649 0 0         while (curr)
650             {
651 0           next = curr->next;
652 0           psFree(curr->serial, pool);
653 0           psFree(curr, pool);
654 0           curr = next;
655             }
656 0           *revoked = NULL;
657 0           }
658              
659 0           static void internalFreeCRL(psX509Crl_t *crl)
660             {
661             psPool_t *pool;
662              
663 0 0         if (crl == NULL)
664             {
665 0           return;
666             }
667             /* test all components for NULL. This is used for freeing during
668             parse so some might not be there at all */
669 0           pool = crl->pool;
670              
671 0           psX509FreeDNStruct(&crl->issuer, pool);
672 0           x509FreeExtensions(&crl->extensions);
673 0           x509FreeRevoked(&crl->revoked, pool);
674 0           psFree(crl->sig, pool);
675 0           psFree(crl->nextUpdate, pool);
676              
677 0           memset(crl, 0, sizeof(psX509Crl_t));
678 0           psFree(crl, pool);
679             }
680              
681 0           void psX509FreeCRL(psX509Crl_t *crl)
682             {
683 0 0         if (crl == NULL)
684             {
685 0           return;
686             }
687             /* Try to delete from g_CRL list first. Will lock table */
688 0 0         if (psCRL_Delete(crl))
689             {
690 0           return;
691             }
692 0           internalFreeCRL(crl);
693             }
694              
695              
696             /* Helper for psX509AuthenticateCRL to see if we have a matching CRL for
697             the given issuer cert */
698 0           static int32 internalMatchIssuer(psX509Cert_t *CA, psX509Crl_t *CRL)
699             {
700             /* Ensure crlSign flag of KeyUsage for the given CA. */
701 0 0         if ( !(CA->extensions.keyUsageFlags & KEY_USAGE_CRL_SIGN))
702             {
703             # ifndef ALLOW_CRL_ISSUERS_WITHOUT_KEYUSAGE
704             /*
705             Fail if there is no keyUsage extension or the cRLSign flag
706             is not set.
707             */
708 0           return PS_CERT_AUTH_FAIL_EXTENSION;
709             # else
710             /*
711             Allow missing cRLSign flag when there is no keyUsage extension.
712             */
713             if (CA->extensions.keyUsageFlags != 0) /* RFC 5280: at least one bit
714             must be 1 when keyUsage
715             is present. */
716             {
717             return PS_CERT_AUTH_FAIL_EXTENSION;
718             }
719             # endif /* !ALLOW_CRL_ISSUERS_WITHOUT_KEYUSAGE */
720             }
721              
722             /* Same DN? */
723 0 0         if (memcmpct(CRL->issuer.hash, CA->subject.hash, SHA1_HASH_SIZE) != 0)
724             {
725             psTraceCrypto("CRL not issued by this CA\n");
726 0           return PS_CERT_AUTH_FAIL_DN;
727             }
728             # ifdef ENFORCE_CRL_AUTH_KEY_ID_EXT
729             /* Same AuthKeyId? */
730             if (CRL->extensions.ak.keyId == NULL)
731             {
732             psTraceCrypto("CRL does not have a AuthKeyId extension\n");
733             return PS_CERT_AUTH_FAIL_EXTENSION;
734             }
735             if (CA->extensions.sk.id == NULL)
736             {
737             psTraceCrypto("CA does not have a SubjectKeyId extension\n");
738             return PS_CERT_AUTH_FAIL_EXTENSION;
739             }
740             if (CRL->extensions.ak.keyLen != CA->extensions.sk.len)
741             {
742             psTraceCrypto("CRL issuer does not have same AuthKeyId as CA\n");
743             return PS_CERT_AUTH_FAIL_EXTENSION;
744             }
745             if (memcmpct(CRL->extensions.ak.keyId, CA->extensions.sk.id,
746             CRL->extensions.ak.keyLen) != 0)
747             {
748             psTraceCrypto("CRL issuer does not have same AuthKeyId as CA\n");
749             return PS_CERT_AUTH_FAIL_EXTENSION;
750             }
751             # endif
752             /* Looks good */
753 0           return 1;
754             }
755              
756             /*
757             NO g_CRL used at all
758              
759             Worth noting that the authenticated state is reset each time this is
760             called so it shouldn't be called blindly in a loop hoping the status
761             will come out correctly.
762              
763             poolUserPtr is for the TMP_PKI pool
764             */
765 0           int32_t psX509AuthenticateCRL(psX509Cert_t *CA, psX509Crl_t *CRL,
766             void *poolUserPtr)
767             {
768             int32 rc;
769              
770 0           psBool_t verifyResult = PS_FALSE;
771             psVerifySigOptions_t opts;
772              
773 0 0         if (CA == NULL || CRL == NULL)
    0          
774             {
775 0           return PS_ARG_FAIL;
776             }
777 0           if (CRL->authenticated == 1)
778             {
779             /* Going to have to assume caller knows what they are doing */
780             psTraceCrypto("WARNING: this CRL has already been authenticated\n");
781             }
782 0           CRL->authenticated = PS_FALSE;
783              
784             /* A few tests to see if this CA is the true issuer of the CRL */
785 0 0         if ((rc = internalMatchIssuer(CA, CRL)) < 0)
786             {
787 0           return rc;
788             }
789              
790             /* Perform the signature verification. */
791 0           memset(&opts, 0, sizeof(psVerifySigOptions_t));
792 0           rc = psVerifySig(NULL,
793 0           CRL->sigHash, CRL->sigHashLen,
794 0           CRL->sig, CRL->sigLen,
795             &CA->publicKey,
796             CRL->sigAlg,
797             &verifyResult,
798             &opts);
799 0 0         if (rc != PS_SUCCESS)
800             {
801 0 0         if (verifyResult == PS_FALSE)
802             {
803             psTraceCrypto("Unable to verify CRL signature\n");
804 0           return PS_CERT_AUTH_FAIL_SIG;
805             }
806             else
807             {
808             psTraceIntCrypto("psVerifySig failed: %d\n", rc);
809 0           return rc;
810             }
811             }
812              
813 0 0         if (verifyResult == PS_TRUE)
814             {
815 0           CRL->authenticated = PS_TRUE;
816             }
817              
818 0           return PS_SUCCESS;
819             }
820              
821 0           int32 psX509GetCRLVersion(const unsigned char *crlBin, int32 crlBinLen)
822             {
823             int version;
824             uint32_t glen, tbsCertLen;
825 0           const unsigned char *end, *p = crlBin;
826              
827 0 0         if (crlBin == NULL || crlBinLen <= 0)
    0          
828             {
829 0           return PS_ARG_FAIL;
830             }
831 0           end = p + crlBinLen;
832 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &glen, 0) < 0)
833             {
834             psTraceCrypto("Initial parse error in psX509GetCRLVersion\n");
835 0           return PS_PARSE_FAIL;
836             }
837 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &tbsCertLen, 0) < 0)
838             {
839             psTraceCrypto("Initial parse error in psX509GetCRLVersion\n");
840 0           return PS_PARSE_FAIL;
841             }
842 0 0         if (end > p && *p == ASN_INTEGER)
    0          
843             {
844 0           version = 0;
845 0 0         if (getAsnInteger(&p, (uint32) (end - p), &version) < 0 || version < 0)
    0          
846             {
847             psTraceCrypto("Version parse error in psX509GetCRLVersion.\n");
848 0           return PS_PARSE_FAIL;
849             }
850 0           return (int32) version;
851             }
852 0           return 1; /* Default version (v2). */
853             }
854              
855             /*
856             Parse a CRL.
857             */
858 0           int32 psX509ParseCRL(psPool_t *pool, psX509Crl_t **crl, unsigned char *crlBin,
859             int32 crlBinLen)
860             {
861 0           const unsigned char *end, *start, *sigStart, *sigEnd, *revStart, *p = crlBin;
862             int32 oi, version, rc;
863             x509revoked_t *curr, *next;
864             psX509Crl_t *lcrl;
865             uint32_t glen, ilen, tbsCertLen;
866             psSize_t timelen, plen;
867             unsigned char timetag;
868              
869 0 0         if (crlBin == NULL || crlBinLen <= 0)
    0          
870             {
871 0           return PS_ARG_FAIL;
872             }
873 0           end = p + crlBinLen;
874             /*
875             CertificateList ::= SEQUENCE {
876             tbsCertList TBSCertList,
877             signatureAlgorithm AlgorithmIdentifier,
878             signatureValue BIT STRING }
879              
880             TBSCertList ::= SEQUENCE {
881             version Version OPTIONAL,
882             -- if present, shall be v2
883             signature AlgorithmIdentifier,
884             issuer Name,
885             thisUpdate Time,
886             nextUpdate Time OPTIONAL,
887             revokedCertificates SEQUENCE OF SEQUENCE {
888             userCertificate CertificateSerialNumber,
889             revocationDate Time,
890             crlEntryExtensions Extensions OPTIONAL
891             -- if present, shall be v2
892             } OPTIONAL,
893             crlExtensions [0] EXPLICIT Extensions OPTIONAL
894             -- if present, shall be v2
895             }
896             */
897 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &glen, 0) < 0)
898             {
899             psTraceCrypto("Initial parse error in psX509ParseCRL\n");
900 0           return PS_PARSE_FAIL;
901             }
902              
903             /* Track tbsCert for signature purposes and for encoding where there
904             is no revokedCertificate entry */
905 0           sigStart = p;
906 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &tbsCertLen, 0) < 0)
907             {
908             psTraceCrypto("Initial parse error in psX509ParseCRL\n");
909 0           return PS_PARSE_FAIL;
910             }
911 0           start = p;
912 0 0         if (end > p && *p == ASN_INTEGER)
    0          
913             {
914 0           version = 0;
915 0 0         if (getAsnInteger(&p, (uint32) (end - p), &version) < 0 || version < 0)
    0          
916             {
917             psTraceCrypto("Version parse error in psX509ParseCRL.\n");
918 0           return PS_PARSE_FAIL;
919             }
920 0 0         if (version != 1)
921             {
922             psTraceIntCrypto("Version parse: unsupported version requested: "
923             "%d\n", version);
924 0           return PS_VERSION_UNSUPPORTED;
925             }
926             }
927              
928             /* looking correct. Allocate the psX509Crl_t */
929 0 0         if ((lcrl = psMalloc(pool, sizeof(psX509Crl_t))) == NULL)
930             {
931 0           return PS_MEM_FAIL;
932             }
933 0           memset(lcrl, 0, sizeof(psX509Crl_t));
934 0           lcrl->pool = pool;
935              
936             /* signature */
937 0 0         if (getAsnAlgorithmIdentifier(&p, (int32) (end - p), &lcrl->sigAlg, &plen)
938             < 0)
939             {
940             psTraceCrypto("Couldn't parse crl sig algorithm identifier\n");
941 0           psX509FreeCRL(lcrl);
942 0           return PS_PARSE_FAIL;
943             }
944              
945             /*
946             Name ::= CHOICE { -- only one possibility for now --
947             rdnSequence RDNSequence }
948              
949             RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
950              
951             DistinguishedName ::= RDNSequence
952              
953             RelativeDistinguishedName ::=
954             SET SIZE (1 .. MAX) OF AttributeTypeAndValue
955             */
956 0 0         if ((rc = psX509GetDNAttributes(pool, &p, (uint32) (end - p),
957             &lcrl->issuer, 0)) < 0)
958             {
959 0           psX509FreeCRL(lcrl);
960             psTraceCrypto("Couldn't parse crl issuer DN attributes\n");
961 0           return rc;
962             }
963              
964             /* thisUpdate TIME */
965 0 0         if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME)))
    0          
    0          
966             {
967             psTraceCrypto("Malformed thisUpdate CRL\n");
968 0           psX509FreeCRL(lcrl);
969 0           return PS_PARSE_FAIL;
970             }
971 0           timetag = *p;
972 0           p++;
973 0 0         if (getAsnLength(&p, (uint32) (end - p), &timelen) < 0 ||
    0          
974 0           (uint32) (end - p) < timelen)
975             {
976             psTraceCrypto("Malformed thisUpdate CRL\n");
977 0           psX509FreeCRL(lcrl);
978 0           return PS_PARSE_FAIL;
979             }
980 0 0         if (psBrokenDownTimeImport(
    0          
981             &lcrl->thisUpdateBDT, (const char *) p, timelen,
982             timetag == ASN_UTCTIME ?
983             PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0) != PS_SUCCESS)
984             {
985             psTraceCrypto("Malformed thisUpdate CRL\n");
986 0           psX509FreeCRL(lcrl);
987 0           return PS_PARSE_FAIL;
988             }
989              
990 0           p += timelen; /* Move p beyond thisUpdate TIME. */
991              
992             /* nextUpdateTIME - Optional... but required by spec */
993 0 0         if ((end - p) < 1 || ((*p == ASN_UTCTIME) || (*p == ASN_GENERALIZEDTIME)))
    0          
    0          
994             {
995 0           lcrl->nextUpdateType = timetag = *p;
996 0           p++;
997 0 0         if (getAsnLength(&p, (uint32) (end - p), &timelen) < 0 ||
    0          
998 0           (uint32) (end - p) < timelen)
999             {
1000             psTraceCrypto("Malformed nextUpdateTIME CRL\n");
1001 0           psX509FreeCRL(lcrl);
1002 0           return PS_PARSE_FAIL;
1003             }
1004 0 0         if ((lcrl->nextUpdate = psMalloc(pool, timelen + 1)) == NULL)
1005             {
1006 0           psX509FreeCRL(lcrl);
1007 0           return PS_PARSE_FAIL;
1008             }
1009 0           memcpy(lcrl->nextUpdate, p, timelen);
1010 0           lcrl->nextUpdate[timelen] = '\0';
1011              
1012 0 0         if (psBrokenDownTimeImport(
    0          
1013             &lcrl->nextUpdateBDT, (const char *) p, timelen,
1014             timetag == ASN_UTCTIME ?
1015             PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0) != PS_SUCCESS)
1016             {
1017             psTraceCrypto("Malformed thisUpdate CRL\n");
1018 0           psX509FreeCRL(lcrl);
1019 0           return PS_PARSE_FAIL;
1020             }
1021 0           p += timelen;
1022              
1023             /* Note: nextUpdate may be in past, but parsing does not
1024             check that. */
1025             }
1026             else
1027             {
1028 0           memset(&lcrl->nextUpdateBDT, 0, sizeof(lcrl->nextUpdateBDT));
1029             }
1030              
1031             /* Need to see if any data left in tbsCertList. Could be no revocations */
1032 0 0         if ((p - start) != tbsCertLen)
1033             {
1034             /*
1035             revokedCertificates SEQUENCE OF SEQUENCE {
1036             userCertificate CertificateSerialNumber,
1037             revocationDate Time,
1038             crlEntryExtensions Extensions OPTIONAL
1039             -- if present, shall be v2
1040             } OPTIONAL,
1041             */
1042              
1043             /* Need to peek at next byte to make sure there are some revoked
1044             certs here. Could be jumping right to crlExtensions */
1045 0 0         if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 0))
1046             {
1047              
1048 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &glen, 0) < 0)
1049             {
1050             psTraceCrypto("Initial revokedCert error in psX509ParseCRL\n");
1051 0           psX509FreeCRL(lcrl);
1052 0           return PS_PARSE_FAIL;
1053             }
1054              
1055 0           lcrl->revoked = curr = psMalloc(pool, sizeof(x509revoked_t));
1056 0 0         if (curr == NULL)
1057             {
1058 0           psX509FreeCRL(lcrl);
1059 0           return PS_MEM_FAIL;
1060             }
1061 0           memset(curr, 0x0, sizeof(x509revoked_t));
1062 0 0         while (glen > 0)
1063             {
1064 0           revStart = p;
1065 0 0         if (getAsnSequence32(&p, (uint32) (end - p), &ilen, 0) < 0)
1066             {
1067             psTraceCrypto("Deep revokedCert error in psX509ParseCRL\n");
1068 0           psX509FreeCRL(lcrl);
1069 0           return PS_PARSE_FAIL;
1070             }
1071 0           start = p; /* reusing start */
1072 0 0         if ((rc = getSerialNum(pool, &p, ilen, &curr->serial,
1073             &curr->serialLen)) < 0)
1074             {
1075             psTraceCrypto("ASN serial number parse error\n");
1076 0           psX509FreeCRL(lcrl);
1077 0           return rc;
1078             }
1079              
1080             /* revocationDate */
1081 0 0         if ((end - p) < 1 || ((*p != ASN_UTCTIME) &&
    0          
    0          
1082 0           (*p != ASN_GENERALIZEDTIME)))
1083             {
1084             psTraceCrypto("Malformed revocationDate CRL\n");
1085 0           psX509FreeCRL(lcrl);
1086 0           return PS_PARSE_FAIL;
1087             }
1088 0           timetag = *p;
1089 0           p++;
1090 0 0         if (getAsnLength(&p, (uint32) (end - p), &timelen) < 0 ||
    0          
1091 0           (uint32) (end - p) < timelen)
1092             {
1093             psTraceCrypto("Malformed thisUpdate CRL\n");
1094 0           psX509FreeCRL(lcrl);
1095 0           return PS_PARSE_FAIL;
1096             }
1097 0 0         if (psBrokenDownTimeImport(
    0          
1098             &curr->revocationDateBDT, (const char *) p,
1099             timelen,
1100             timetag == ASN_UTCTIME ?
1101             PS_BROKENDOWN_TIME_IMPORT_2DIGIT_YEAR : 0) !=
1102             PS_SUCCESS)
1103             {
1104             psTraceCrypto("Malformed thisUpdate CRL\n");
1105 0           psX509FreeCRL(lcrl);
1106 0           return PS_PARSE_FAIL;
1107             }
1108              
1109             /* skipping crlEntryExtensions */
1110 0           p += ilen - (uint32) (p - start);
1111 0 0         if (glen < (uint32) (p - revStart))
1112             {
1113             psTraceCrypto("Deeper revokedCert err in psX509ParseCRL\n");
1114 0           psX509FreeCRL(lcrl);
1115 0           return PS_PARSE_FAIL;
1116             }
1117 0           glen -= (uint32) (p - revStart);
1118              
1119             /* psTraceBytes("revoked", curr->serial, curr->serialLen); */
1120 0 0         if (glen > 0)
1121             {
1122 0 0         if ((next = psMalloc(pool, sizeof(x509revoked_t))) == NULL)
1123             {
1124 0           psX509FreeCRL(lcrl);
1125 0           return PS_MEM_FAIL;
1126             }
1127 0           memset(next, 0x0, sizeof(x509revoked_t));
1128 0           curr->next = next;
1129 0           curr = next;
1130             }
1131             }
1132             }
1133             /* Always treated as OPTIONAL */
1134 0 0         if (getExplicitExtensions(pool, &p, (uint32) (end - p), 0,
1135             &lcrl->extensions, 0) < 0)
1136             {
1137             psTraceCrypto("Extension parse error in psX509ParseCRL\n");
1138 0           psX509FreeCRL(lcrl);
1139 0           return PS_PARSE_FAIL;
1140             }
1141             /* if (lcrl->extensions.ak.keyId) { */
1142             /* psTraceBytes("CRL ak", lcrl->extensions.ak.keyId, 20); */
1143             /* } */
1144             } /* End tbsCertList */
1145 0           sigEnd = p;
1146              
1147 0 0         if (getAsnAlgorithmIdentifier(&p, (int32) (end - p), &oi, &plen) < 0)
1148             {
1149 0           psX509FreeCRL(lcrl);
1150             psTraceCrypto("Couldn't parse crl sig algorithm identifier\n");
1151 0           return PS_PARSE_FAIL;
1152             }
1153             /* must match */
1154 0 0         if (oi != lcrl->sigAlg)
1155             {
1156             psTraceCrypto("Couldn't match crl sig algorithm identifier\n");
1157 0           psX509FreeCRL(lcrl);
1158 0           return PS_PARSE_FAIL;
1159             }
1160              
1161 0 0         if ((rc = psX509GetSignature(pool, &p, (uint32) (end - p), &lcrl->sig,
1162             &lcrl->sigLen)) < 0)
1163             {
1164 0           psX509FreeCRL(lcrl);
1165             psTraceCrypto("Couldn't parse signature\n");
1166 0           return rc;
1167             }
1168              
1169             /* Perform the hashing for later auth */
1170 0           rc = psComputeHashForSig(sigStart, sigEnd - sigStart,
1171             lcrl->sigAlg,
1172 0           lcrl->sigHash, &lcrl->sigHashLen);
1173 0 0         if (rc != PS_SUCCESS)
1174             {
1175 0           psX509FreeCRL(lcrl);
1176 0           return rc;
1177             }
1178              
1179 0           *crl = lcrl;
1180              
1181 0           return PS_SUCCESS;
1182             }
1183              
1184             /*
1185             If the provided cert has a URL based CRL Distribution point, return
1186             that. The url and urlLen point directly into the cert structure so
1187             must not be modified.
1188             */
1189 0           int32 psX509GetCRLdistURL(psX509Cert_t *cert, char **url, uint32_t *urlLen)
1190             {
1191             x509GeneralName_t *gn;
1192              
1193 0 0         if (cert == NULL)
1194             {
1195 0           return PS_ARG_FAIL;
1196             }
1197 0           *url = NULL;
1198 0           *urlLen = 0;
1199              
1200 0 0         if (cert->extensions.crlDist != NULL)
1201             {
1202 0           gn = cert->extensions.crlDist;
1203 0 0         while (gn)
1204             {
1205 0 0         if (gn->id == 6) /* Only pass on URI types */
1206             {
1207 0           *url = (char *) gn->data;
1208 0           *urlLen = gn->dataLen;
1209 0           return PS_TRUE;
1210             }
1211             else
1212             {
1213             psTraceIntCrypto("Unsupported CRL distro point format %d\n",
1214             gn->id);
1215             }
1216 0           gn = gn->next;
1217             }
1218             }
1219 0           return PS_FALSE;
1220             }
1221              
1222             /******************************************************************************/
1223              
1224             # endif /* USE_CERT_PARSE */
1225             #endif /* USE_CRL */
1226