cyassl re-port with cellular comms, PSK test

Dependencies:   VodafoneUSBModem_bleedingedge2 mbed-rtos mbed-src

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