3 * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
5 * This file is part of CyaSSL.
7 * CyaSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * CyaSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
29 #include <cyassl/internal.h>
30 #include <cyassl/error.h>
36 /* Initialze CRL members */
37 int InitCRL(CYASSL_CRL* crl, CYASSL_CERT_MANAGER* cm)
39 CYASSL_ENTER("InitCRL");
43 crl->monitors[0].path = NULL;
44 crl->monitors[1].path = NULL;
45 #ifdef HAVE_CRL_MONITOR
48 if (InitMutex(&crl->crlLock) != 0)
49 return BAD_MUTEX_ERROR;
55 /* Initialze CRL Entry */
56 static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
58 CYASSL_ENTER("InitCRL_Entry");
60 XMEMCPY(crle->issuerHash, dcrl->issuerHash, SHA_DIGEST_SIZE);
61 XMEMCPY(crle->crlHash, dcrl->crlHash, MD5_DIGEST_SIZE);
62 XMEMCPY(crle->lastDate, dcrl->lastDate, MAX_DATE_SIZE);
63 XMEMCPY(crle->nextDate, dcrl->nextDate, MAX_DATE_SIZE);
64 crle->lastDateFormat = dcrl->lastDateFormat;
65 crle->nextDateFormat = dcrl->nextDateFormat;
67 crle->certs = dcrl->certs; /* take ownsership */
69 crle->totalCerts = dcrl->totalCerts;
75 /* Free all CRL Entry resources */
76 static void FreeCRL_Entry(CRL_Entry* crle)
78 RevokedCert* tmp = crle->certs;
80 CYASSL_ENTER("FreeCRL_Entry");
83 RevokedCert* next = tmp->next;
84 XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
91 /* Free all CRL resources */
92 void FreeCRL(CYASSL_CRL* crl)
94 CRL_Entry* tmp = crl->crlList;
96 CYASSL_ENTER("FreeCRL");
98 if (crl->monitors[0].path)
99 XFREE(crl->monitors[0].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
101 if (crl->monitors[1].path)
102 XFREE(crl->monitors[1].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
105 CRL_Entry* next = tmp->next;
107 XFREE(tmp, NULL, DYNAMIC_TYPE_CRL_ENTRY);
111 #ifdef HAVE_CRL_MONITOR
113 CYASSL_MSG("Canceling monitor thread");
114 pthread_cancel(crl->tid);
117 FreeMutex(&crl->crlLock);
121 /* Is the cert ok with CRL, return 0 on success */
122 int CheckCertCRL(CYASSL_CRL* crl, DecodedCert* cert)
129 CYASSL_ENTER("CheckCertCRL");
131 if (LockMutex(&crl->crlLock) != 0) {
132 CYASSL_MSG("LockMutex failed");
133 return BAD_MUTEX_ERROR;
139 if (XMEMCMP(crle->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0) {
140 CYASSL_MSG("Found CRL Entry on list");
141 CYASSL_MSG("Checking next date validity");
143 if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
144 CYASSL_MSG("CRL next date is no longer valid");
145 ret = ASN_AFTER_DATE_E;
155 RevokedCert* rc = crle->certs;
158 if (XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) {
159 CYASSL_MSG("Cert revoked");
161 ret = CRL_CERT_REVOKED;
168 UnLockMutex(&crl->crlLock);
170 if (foundEntry == 0) {
171 CYASSL_MSG("Couldn't find CRL for status check");
173 if (crl->cm->cbMissingCRL) {
176 CYASSL_MSG("Issuing missing CRL callback");
178 if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
179 XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
180 url[cert->extCrlInfoSz] = '\0';
183 CYASSL_MSG("CRL url too long");
185 crl->cm->cbMissingCRL(url);
194 /* Add Decoded CRL, 0 on success */
195 static int AddCRL(CYASSL_CRL* crl, DecodedCRL* dcrl)
199 CYASSL_ENTER("AddCRL");
201 crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
203 CYASSL_MSG("alloc CRL Entry failed");
207 if (InitCRL_Entry(crle, dcrl) < 0) {
208 CYASSL_MSG("Init CRL Entry failed");
209 XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
213 if (LockMutex(&crl->crlLock) != 0) {
214 CYASSL_MSG("LockMutex failed");
216 XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
217 return BAD_MUTEX_ERROR;
219 crle->next = crl->crlList;
221 UnLockMutex(&crl->crlLock);
227 /* Load CRL File of type, SSL_SUCCESS on ok */
228 int BufferLoadCRL(CYASSL_CRL* crl, const byte* buff, long sz, int type)
230 int ret = SSL_SUCCESS;
231 const byte* myBuffer = buff; /* if DER ok, otherwise switch */
237 CYASSL_ENTER("BufferLoadCRL");
239 if (crl == NULL || buff == NULL || sz == 0)
242 if (type == SSL_FILETYPE_PEM) {
243 int eccKey = 0; /* not used */
247 ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
249 myBuffer = der.buffer;
253 CYASSL_MSG("Pem to Der failed");
258 InitDecodedCRL(&dcrl);
259 ret = ParseCRL(&dcrl, myBuffer, sz, crl->cm);
261 CYASSL_MSG("ParseCRL error");
264 ret = AddCRL(crl, &dcrl);
266 CYASSL_MSG("AddCRL error");
269 FreeDecodedCRL(&dcrl);
272 XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
275 return SSL_SUCCESS; /* convert */
280 #ifdef HAVE_CRL_MONITOR
283 /* read in new CRL entries and save new list */
284 static int SwapLists(CYASSL_CRL* crl)
290 if (InitCRL(&tmp, crl->cm) < 0) {
291 CYASSL_MSG("Init tmp CRL failed");
295 if (crl->monitors[0].path) {
296 ret = LoadCRL(&tmp, crl->monitors[0].path, SSL_FILETYPE_PEM, 0);
297 if (ret != SSL_SUCCESS) {
298 CYASSL_MSG("PEM LoadCRL on dir change failed");
304 if (crl->monitors[1].path) {
305 ret = LoadCRL(&tmp, crl->monitors[1].path, SSL_FILETYPE_ASN1, 0);
306 if (ret != SSL_SUCCESS) {
307 CYASSL_MSG("DER LoadCRL on dir change failed");
313 if (LockMutex(&crl->crlLock) != 0) {
314 CYASSL_MSG("LockMutex failed");
319 newList = tmp.crlList;
322 tmp.crlList = crl->crlList;
323 crl->crlList = newList;
325 UnLockMutex(&crl->crlLock);
335 #include <sys/event.h>
336 #include <sys/time.h>
339 /* OS X monitoring */
340 static void* DoMonitor(void* arg)
343 struct kevent change;
345 CYASSL_CRL* crl = (CYASSL_CRL*)arg;
347 CYASSL_ENTER("DoMonitor");
351 CYASSL_MSG("kqueue failed");
358 if (crl->monitors[0].path) {
359 fPEM = open(crl->monitors[0].path, O_EVTONLY);
361 CYASSL_MSG("PEM event dir open failed");
366 if (crl->monitors[1].path) {
367 fDER = open(crl->monitors[1].path, O_EVTONLY);
369 CYASSL_MSG("DER event dir open failed");
375 EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
376 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
379 EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
380 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
384 int numEvents = kevent(kq, &change, 1, &event, 1, NULL);
386 CYASSL_MSG("Got kevent");
388 if (numEvents == -1) {
389 CYASSL_MSG("kevent problem, continue");
393 if (SwapLists(crl) < 0) {
394 CYASSL_MSG("SwapLists problem, continue");
404 #include <sys/types.h>
405 #include <sys/inotify.h>
408 /* linux monitoring */
409 static void* DoMonitor(void* arg)
413 CYASSL_CRL* crl = (CYASSL_CRL*)arg;
415 CYASSL_ENTER("DoMonitor");
417 notifyFd = inotify_init();
419 CYASSL_MSG("inotify failed");
423 if (crl->monitors[0].path) {
424 wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
427 CYASSL_MSG("PEM notify add watch failed");
432 if (crl->monitors[1].path) {
433 wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
436 CYASSL_MSG("DER notify add watch failed");
443 int length = read(notifyFd, buffer, sizeof(buffer));
445 CYASSL_MSG("Got notify event");
448 CYASSL_MSG("notify read problem, continue");
452 if (SwapLists(crl) < 0) {
453 CYASSL_MSG("SwapLists problem, continue");
462 #endif /* MACH or linux */
465 /* Start Monitoring the CRL path(s) in a thread */
466 static int StartMonitorCRL(CYASSL_CRL* crl)
470 CYASSL_ENTER("StartMonitorCRL");
476 CYASSL_MSG("Monitor thread already running");
477 return MONITOR_RUNNING_E;
480 pthread_attr_init(&attr);
482 if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
483 CYASSL_MSG("Thread creation error");
484 return THREAD_CREATE_E;
491 #else /* HAVE_CRL_MONITOR */
493 static int StartMonitorCRL(CYASSL_CRL* crl)
495 CYASSL_ENTER("StartMonitorCRL");
496 CYASSL_MSG("Not compiled in");
498 return NOT_COMPILED_IN;
501 #endif /* HAVE_CRL_MONITOR */
504 /* Load CRL path files of type, SSL_SUCCESS on ok */
505 int LoadCRL(CYASSL_CRL* crl, const char* path, int type, int monitor)
507 struct dirent* entry;
509 int ret = SSL_SUCCESS;
511 CYASSL_ENTER("LoadCRL");
517 CYASSL_MSG("opendir path crl load failed");
518 return BAD_PATH_ERROR;
520 while ( (entry = readdir(dir)) != NULL) {
521 if (entry->d_type & DT_REG) {
522 char name[MAX_FILENAME_SZ];
524 if (type == SSL_FILETYPE_PEM) {
525 if (strstr(entry->d_name, ".pem") == NULL) {
526 CYASSL_MSG("not .pem file, skipping");
531 if (strstr(entry->d_name, ".der") == NULL &&
532 strstr(entry->d_name, ".crl") == NULL) {
534 CYASSL_MSG("not .der or .crl file, skipping");
539 XMEMSET(name, 0, sizeof(name));
540 XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 2);
541 XSTRNCAT(name, "/", 1);
542 XSTRNCAT(name, entry->d_name, MAX_FILENAME_SZ/2);
544 if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
546 CYASSL_MSG("CRL file load failed, continuing");
551 if (monitor & CYASSL_CRL_MONITOR) {
552 CYASSL_MSG("monitor path requested");
554 if (type == SSL_FILETYPE_PEM) {
555 crl->monitors[0].path = strdup(path);
556 crl->monitors[0].type = SSL_FILETYPE_PEM;
557 if (crl->monitors[0].path == NULL)
560 crl->monitors[1].path = strdup(path);
561 crl->monitors[1].type = SSL_FILETYPE_ASN1;
562 if (crl->monitors[1].path == NULL)
566 if (monitor & CYASSL_CRL_START_MON) {
567 CYASSL_MSG("start monitoring requested");
569 ret = StartMonitorCRL(crl);
576 #endif /* HAVE_CRL */