This is a port of cyaSSL 2.7.0.

Dependents:   CyaSSL_DTLS_Cellular CyaSSL_DTLS_Ethernet

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers crl.c Source File

crl.c

00001 /* crl.c
00002  *
00003  * Copyright (C) 2006-2013 wolfSSL Inc.
00004  *
00005  * This file is part of CyaSSL.
00006  *
00007  * CyaSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * CyaSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00020  */
00021 
00022 #ifdef HAVE_CONFIG_H
00023     #include <config.h>
00024 #endif
00025 
00026 #include <cyassl/ctaocrypt/settings.h>
00027 
00028 #ifdef HAVE_CRL
00029 
00030 #include <cyassl/internal.h>
00031 #include <cyassl/ctaoerror.h>
00032 
00033 #include <dirent.h>
00034 #include <sys/stat.h>
00035 #include <string.h>
00036 
00037 
00038 /* Initialze CRL members */
00039 int InitCRL(CYASSL_CRL* crl, CYASSL_CERT_MANAGER* cm)
00040 {
00041     CYASSL_ENTER("InitCRL");
00042 
00043     crl->cm = cm;
00044     crl->crlList = NULL;
00045     crl->monitors[0].path = NULL;
00046     crl->monitors[1].path = NULL;
00047 #ifdef HAVE_CRL_MONITOR
00048     crl->tid = 0;
00049 #endif
00050     if (InitMutex(&crl->crlLock) != 0)
00051         return BAD_MUTEX_ERROR; 
00052 
00053     return 0;
00054 }
00055 
00056 
00057 /* Initialze CRL Entry */
00058 static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
00059 {
00060     CYASSL_ENTER("InitCRL_Entry");
00061 
00062     XMEMCPY(crle->issuerHash, dcrl->issuerHash, SHA_DIGEST_SIZE);
00063     /* XMEMCPY(crle->crlHash, dcrl->crlHash, SHA_DIGEST_SIZE);
00064      *   copy the hash here if needed for optimized comparisons */
00065     XMEMCPY(crle->lastDate, dcrl->lastDate, MAX_DATE_SIZE);
00066     XMEMCPY(crle->nextDate, dcrl->nextDate, MAX_DATE_SIZE);
00067     crle->lastDateFormat = dcrl->lastDateFormat;
00068     crle->nextDateFormat = dcrl->nextDateFormat;
00069 
00070     crle->certs = dcrl->certs;   /* take ownsership */
00071     dcrl->certs = NULL;
00072     crle->totalCerts = dcrl->totalCerts;
00073 
00074     return 0;
00075 }
00076 
00077 
00078 /* Free all CRL Entry resources */
00079 static void FreeCRL_Entry(CRL_Entry* crle)
00080 {
00081     RevokedCert* tmp = crle->certs; 
00082 
00083     CYASSL_ENTER("FreeCRL_Entry");
00084 
00085     while(tmp) {
00086         RevokedCert* next = tmp->next;
00087         XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
00088         tmp = next;
00089     }
00090 }
00091 
00092 
00093 
00094 /* Free all CRL resources */
00095 void FreeCRL(CYASSL_CRL* crl, int dynamic)
00096 {
00097     CRL_Entry* tmp = crl->crlList;
00098 
00099     CYASSL_ENTER("FreeCRL");
00100 
00101     if (crl->monitors[0].path)
00102         XFREE(crl->monitors[0].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
00103 
00104     if (crl->monitors[1].path)
00105         XFREE(crl->monitors[1].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
00106 
00107     while(tmp) {
00108         CRL_Entry* next = tmp->next;
00109         FreeCRL_Entry(tmp);
00110         XFREE(tmp, NULL, DYNAMIC_TYPE_CRL_ENTRY);
00111         tmp = next;
00112     }   
00113 
00114 #ifdef HAVE_CRL_MONITOR
00115     if (crl->tid != 0) {
00116         CYASSL_MSG("Canceling monitor thread");
00117         pthread_cancel(crl->tid);
00118     }
00119 #endif
00120     FreeMutex(&crl->crlLock);
00121     if (dynamic)   /* free self */
00122         XFREE(crl, NULL, DYNAMIC_TYPE_CRL);
00123 }
00124 
00125 
00126 /* Is the cert ok with CRL, return 0 on success */
00127 int CheckCertCRL(CYASSL_CRL* crl, DecodedCert* cert)
00128 {
00129     CRL_Entry* crle;
00130     int        foundEntry = 0;
00131     int        ret = 0;
00132 
00133     CYASSL_ENTER("CheckCertCRL");
00134 
00135     if (LockMutex(&crl->crlLock) != 0) {
00136         CYASSL_MSG("LockMutex failed");
00137         return BAD_MUTEX_ERROR;
00138     }
00139 
00140     crle = crl->crlList;
00141 
00142     while (crle) {
00143         if (XMEMCMP(crle->issuerHash, cert->issuerHash, SHA_DIGEST_SIZE) == 0) {
00144             CYASSL_MSG("Found CRL Entry on list");
00145             CYASSL_MSG("Checking next date validity");
00146 
00147             if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
00148                 CYASSL_MSG("CRL next date is no longer valid");
00149                 ret = ASN_AFTER_DATE_E;
00150             }
00151             else
00152                 foundEntry = 1;
00153             break;
00154         }
00155         crle = crle->next;
00156     }
00157 
00158     if (foundEntry) {
00159         RevokedCert* rc = crle->certs;
00160 
00161         while (rc) {
00162             if (XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) {
00163                 CYASSL_MSG("Cert revoked");
00164                 ret = CRL_CERT_REVOKED;
00165                 break;
00166             }
00167             rc = rc->next;  
00168         }
00169     }
00170 
00171     UnLockMutex(&crl->crlLock);
00172 
00173     if (foundEntry == 0) {
00174         CYASSL_MSG("Couldn't find CRL for status check");
00175         ret = CRL_MISSING;
00176         if (crl->cm->cbMissingCRL) {
00177             char url[256];
00178 
00179             CYASSL_MSG("Issuing missing CRL callback");
00180             url[0] = '\0';
00181             if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
00182                 XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
00183                 url[cert->extCrlInfoSz] = '\0';
00184             }
00185             else  {
00186                 CYASSL_MSG("CRL url too long");
00187             }
00188             crl->cm->cbMissingCRL(url);
00189         }
00190     }
00191 
00192 
00193     return ret; 
00194 }
00195 
00196 
00197 /* Add Decoded CRL, 0 on success */
00198 static int AddCRL(CYASSL_CRL* crl, DecodedCRL* dcrl)
00199 {
00200     CRL_Entry* crle;
00201 
00202     CYASSL_ENTER("AddCRL");
00203 
00204     crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
00205     if (crle == NULL) {
00206         CYASSL_MSG("alloc CRL Entry failed");
00207         return -1;
00208     }
00209 
00210     if (InitCRL_Entry(crle, dcrl) < 0) {
00211         CYASSL_MSG("Init CRL Entry failed");
00212         XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
00213         return -1;
00214     }
00215 
00216     if (LockMutex(&crl->crlLock) != 0) {
00217         CYASSL_MSG("LockMutex failed");
00218         FreeCRL_Entry(crle);
00219         XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
00220         return BAD_MUTEX_ERROR;
00221     }
00222     crle->next = crl->crlList;
00223     crl->crlList = crle;
00224     UnLockMutex(&crl->crlLock);
00225 
00226     return 0;
00227 }
00228 
00229 
00230 /* Load CRL File of type, SSL_SUCCESS on ok */
00231 int BufferLoadCRL(CYASSL_CRL* crl, const byte* buff, long sz, int type)
00232 {
00233     int          ret = SSL_SUCCESS;
00234     const byte*  myBuffer = buff;    /* if DER ok, otherwise switch */
00235     buffer       der;
00236     DecodedCRL   dcrl;
00237 
00238     der.buffer = NULL;
00239 
00240     CYASSL_ENTER("BufferLoadCRL");
00241 
00242     if (crl == NULL || buff == NULL || sz == 0)
00243         return BAD_FUNC_ARG;
00244 
00245     if (type == SSL_FILETYPE_PEM) {
00246         int eccKey = 0;   /* not used */
00247         EncryptedInfo info;
00248         info.ctx = NULL;
00249 
00250         ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
00251         if (ret == 0) {
00252             myBuffer = der.buffer;
00253             sz = der.length;
00254         }
00255         else {
00256             CYASSL_MSG("Pem to Der failed");
00257             return -1;
00258         }
00259     }
00260 
00261     InitDecodedCRL(&dcrl);
00262     ret = ParseCRL(&dcrl, myBuffer, (word32)sz, crl->cm);
00263     if (ret != 0) {
00264         CYASSL_MSG("ParseCRL error");
00265     }
00266     else {
00267         ret = AddCRL(crl, &dcrl);
00268         if (ret != 0) {
00269             CYASSL_MSG("AddCRL error");
00270         }
00271     }
00272     FreeDecodedCRL(&dcrl);
00273 
00274     if (der.buffer)
00275         XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
00276 
00277     if (ret == 0)
00278         return SSL_SUCCESS;  /* convert */
00279     return ret;
00280 }
00281 
00282 
00283 #ifdef HAVE_CRL_MONITOR
00284 
00285 
00286 /* read in new CRL entries and save new list */
00287 static int SwapLists(CYASSL_CRL* crl)
00288 {
00289     int        ret;
00290     CYASSL_CRL tmp;
00291     CRL_Entry* newList;
00292 
00293     if (InitCRL(&tmp, crl->cm) < 0) {
00294         CYASSL_MSG("Init tmp CRL failed");
00295         return -1;
00296     }
00297 
00298     if (crl->monitors[0].path) {
00299         ret = LoadCRL(&tmp, crl->monitors[0].path, SSL_FILETYPE_PEM, 0);
00300         if (ret != SSL_SUCCESS) {
00301             CYASSL_MSG("PEM LoadCRL on dir change failed");
00302             FreeCRL(&tmp, 0);
00303             return -1;
00304         }
00305     }
00306 
00307     if (crl->monitors[1].path) {
00308         ret = LoadCRL(&tmp, crl->monitors[1].path, SSL_FILETYPE_ASN1, 0);
00309         if (ret != SSL_SUCCESS) {
00310             CYASSL_MSG("DER LoadCRL on dir change failed");
00311             FreeCRL(&tmp, 0);
00312             return -1;
00313         }
00314     }
00315 
00316     if (LockMutex(&crl->crlLock) != 0) {
00317         CYASSL_MSG("LockMutex failed");
00318         FreeCRL(&tmp, 0);
00319         return -1;
00320     }
00321 
00322     newList = tmp.crlList;
00323 
00324     /* swap lists */
00325     tmp.crlList  = crl->crlList;
00326     crl->crlList = newList;
00327 
00328     UnLockMutex(&crl->crlLock);
00329 
00330     FreeCRL(&tmp, 0);
00331 
00332     return 0;
00333 }
00334 
00335 
00336 #if (defined(__MACH__) || defined(__FreeBSD__))
00337 
00338 #include <sys/types.h>
00339 #include <sys/event.h>
00340 #include <sys/time.h>
00341 #include <fcntl.h>
00342 
00343 #ifdef __MACH__
00344     #define XEVENT_MODE O_EVTONLY
00345 #elif defined(__FreeBSD__)
00346     #define XEVENT_MODE EVFILT_VNODE
00347 #endif
00348 
00349 
00350 /* OS X  monitoring */
00351 static void* DoMonitor(void* arg)
00352 {
00353     int fPEM, fDER, kq;
00354     struct kevent change;
00355 
00356     CYASSL_CRL* crl = (CYASSL_CRL*)arg;
00357 
00358     CYASSL_ENTER("DoMonitor");
00359 
00360     kq = kqueue();
00361     if (kq == -1) {
00362         CYASSL_MSG("kqueue failed");
00363         return NULL;
00364     }
00365 
00366     fPEM = -1;
00367     fDER = -1;
00368 
00369     if (crl->monitors[0].path) {
00370         fPEM = open(crl->monitors[0].path, XEVENT_MODE);
00371         if (fPEM == -1) {
00372             CYASSL_MSG("PEM event dir open failed");
00373             return NULL;
00374         }
00375     }
00376 
00377     if (crl->monitors[1].path) {
00378         fDER = open(crl->monitors[1].path, XEVENT_MODE);
00379         if (fDER == -1) {
00380             CYASSL_MSG("DER event dir open failed");
00381             return NULL;
00382         }
00383     }
00384 
00385     if (fPEM != -1)
00386         EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
00387                 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
00388 
00389     if (fDER != -1)
00390         EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
00391                 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
00392 
00393     for (;;) {
00394         struct kevent event;
00395         int           numEvents = kevent(kq, &change, 1, &event, 1, NULL);
00396        
00397         CYASSL_MSG("Got kevent");
00398 
00399         if (numEvents == -1) {
00400             CYASSL_MSG("kevent problem, continue");
00401             continue;
00402         }
00403 
00404         if (SwapLists(crl) < 0) {
00405             CYASSL_MSG("SwapLists problem, continue");
00406         }
00407     }
00408 
00409     return NULL;
00410 }
00411 
00412 
00413 #elif defined(__linux__)
00414 
00415 #include <sys/types.h>
00416 #include <sys/inotify.h>
00417 #include <unistd.h>
00418 
00419 /* linux monitoring */
00420 static void* DoMonitor(void* arg)
00421 {
00422     int         notifyFd;
00423     int         wd;
00424     CYASSL_CRL* crl = (CYASSL_CRL*)arg;
00425 
00426     CYASSL_ENTER("DoMonitor");
00427 
00428     notifyFd = inotify_init();
00429     if (notifyFd < 0) {
00430         CYASSL_MSG("inotify failed");
00431         return NULL;
00432     }
00433 
00434     if (crl->monitors[0].path) {
00435         wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
00436                                                                 IN_DELETE);
00437         if (wd < 0) {
00438             CYASSL_MSG("PEM notify add watch failed");
00439             return NULL;
00440         }
00441     }
00442 
00443     if (crl->monitors[1].path) {
00444         wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
00445                                                                 IN_DELETE);
00446         if (wd < 0) {
00447             CYASSL_MSG("DER notify add watch failed");
00448             return NULL;
00449         }
00450     }
00451 
00452     for (;;) {
00453         char          buff[8192];
00454         int           length = read(notifyFd, buff, sizeof(buff));
00455        
00456         CYASSL_MSG("Got notify event");
00457 
00458         if (length < 0) {
00459             CYASSL_MSG("notify read problem, continue");
00460             continue;
00461         } 
00462 
00463         if (SwapLists(crl) < 0) {
00464             CYASSL_MSG("SwapLists problem, continue");
00465         }
00466     }
00467 
00468     return NULL;
00469 }
00470 
00471 
00472 #else
00473 
00474 #error "CRL monitor only currently supported on linux or mach"
00475 
00476 #endif /* MACH or linux */
00477 
00478 
00479 /* Start Monitoring the CRL path(s) in a thread */
00480 static int StartMonitorCRL(CYASSL_CRL* crl)
00481 {
00482     pthread_attr_t attr;
00483 
00484     CYASSL_ENTER("StartMonitorCRL");
00485 
00486     if (crl == NULL) 
00487         return BAD_FUNC_ARG;
00488 
00489     if (crl->tid != 0) {
00490         CYASSL_MSG("Monitor thread already running");
00491         return MONITOR_RUNNING_E;
00492     }
00493 
00494     pthread_attr_init(&attr);
00495 
00496     if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
00497         CYASSL_MSG("Thread creation error");
00498         return THREAD_CREATE_E;
00499     }
00500 
00501     return SSL_SUCCESS;
00502 }
00503 
00504 
00505 #else /* HAVE_CRL_MONITOR */
00506 
00507 static int StartMonitorCRL(CYASSL_CRL* crl)
00508 {
00509     (void)crl;
00510 
00511     CYASSL_ENTER("StartMonitorCRL");
00512     CYASSL_MSG("Not compiled in");
00513 
00514     return NOT_COMPILED_IN;
00515 }
00516 
00517 #endif  /* HAVE_CRL_MONITOR */
00518 
00519 
00520 /* Load CRL path files of type, SSL_SUCCESS on ok */ 
00521 int LoadCRL(CYASSL_CRL* crl, const char* path, int type, int monitor)
00522 {
00523     struct dirent* entry;
00524     DIR*   dir;
00525     int    ret = SSL_SUCCESS;
00526 
00527     CYASSL_ENTER("LoadCRL");
00528     if (crl == NULL)
00529         return BAD_FUNC_ARG;
00530 
00531     dir = opendir(path);
00532     if (dir == NULL) {
00533         CYASSL_MSG("opendir path crl load failed");
00534         return BAD_PATH_ERROR;
00535     }
00536     while ( (entry = readdir(dir)) != NULL) {
00537         char name[MAX_FILENAME_SZ];
00538         struct stat s;
00539 
00540         XMEMSET(name, 0, sizeof(name));
00541         XSTRNCPY(name, path, MAX_FILENAME_SZ/2 - 2);
00542         XSTRNCAT(name, "/", 1);
00543         XSTRNCAT(name, entry->d_name, MAX_FILENAME_SZ/2);
00544 
00545         if (stat(name, &s) != 0) {
00546             CYASSL_MSG("stat on name failed");
00547             continue;
00548         }
00549         if (s.st_mode & S_IFREG) {
00550 
00551             if (type == SSL_FILETYPE_PEM) {
00552                 if (strstr(entry->d_name, ".pem") == NULL) {
00553                     CYASSL_MSG("not .pem file, skipping");
00554                     continue;
00555                 }
00556             }
00557             else {
00558                 if (strstr(entry->d_name, ".der") == NULL &&
00559                     strstr(entry->d_name, ".crl") == NULL) {
00560 
00561                     CYASSL_MSG("not .der or .crl file, skipping");
00562                     continue;
00563                 }
00564             }
00565 
00566             if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
00567                                                                != SSL_SUCCESS) {
00568                 CYASSL_MSG("CRL file load failed, continuing");
00569             }
00570         }
00571     }
00572 
00573     if (monitor & CYASSL_CRL_MONITOR) {
00574         CYASSL_MSG("monitor path requested");
00575 
00576         if (type == SSL_FILETYPE_PEM) {
00577             crl->monitors[0].path = strdup(path);
00578             crl->monitors[0].type = SSL_FILETYPE_PEM;
00579             if (crl->monitors[0].path == NULL)
00580                 ret = MEMORY_E;
00581         } else {
00582             crl->monitors[1].path = strdup(path);
00583             crl->monitors[1].type = SSL_FILETYPE_ASN1;
00584             if (crl->monitors[1].path == NULL)
00585                 ret = MEMORY_E;
00586         }
00587       
00588         if (monitor & CYASSL_CRL_START_MON) {
00589             CYASSL_MSG("start monitoring requested");
00590     
00591             ret = StartMonitorCRL(crl);
00592        } 
00593     }
00594     
00595     closedir(dir);
00596 
00597     return ret;
00598 }
00599 
00600 #endif /* HAVE_CRL */