]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/CyaSSL/src/crl.c
40759a4f1d1ce5cd7c9ba5a95e980b24de2a8463
[freertos] / FreeRTOS-Plus / CyaSSL / src / crl.c
1 /* crl.c
2  *
3  * Copyright (C) 2006-2012 Sawtooth Consulting Ltd.
4  *
5  * This file is part of CyaSSL.
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #ifdef HAVE_CONFIG_H
23     #include <config.h>
24 #endif
25
26
27 #ifdef HAVE_CRL
28
29 #include <cyassl/internal.h>
30 #include <cyassl/error.h>
31
32 #include <dirent.h>
33 #include <string.h>
34
35
36 /* Initialze CRL members */
37 int InitCRL(CYASSL_CRL* crl, CYASSL_CERT_MANAGER* cm)
38 {
39     CYASSL_ENTER("InitCRL");
40
41     crl->cm = cm;
42     crl->crlList = NULL;
43     crl->monitors[0].path = NULL;
44     crl->monitors[1].path = NULL;
45 #ifdef HAVE_CRL_MONITOR
46     crl->tid = 0;
47 #endif
48     if (InitMutex(&crl->crlLock) != 0)
49         return BAD_MUTEX_ERROR; 
50
51     return 0;
52 }
53
54
55 /* Initialze CRL Entry */
56 static int InitCRL_Entry(CRL_Entry* crle, DecodedCRL* dcrl)
57 {
58     CYASSL_ENTER("InitCRL_Entry");
59
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;
66
67     crle->certs = dcrl->certs;   /* take ownsership */
68     dcrl->certs = NULL;
69     crle->totalCerts = dcrl->totalCerts;
70
71     return 0;
72 }
73
74
75 /* Free all CRL Entry resources */
76 static void FreeCRL_Entry(CRL_Entry* crle)
77 {
78     RevokedCert* tmp = crle->certs; 
79
80     CYASSL_ENTER("FreeCRL_Entry");
81
82     while(tmp) {
83         RevokedCert* next = tmp->next;
84         XFREE(tmp, NULL, DYNAMIC_TYPE_REVOKED);
85         tmp = next;
86     }
87 }
88
89
90
91 /* Free all CRL resources */
92 void FreeCRL(CYASSL_CRL* crl)
93 {
94     CRL_Entry* tmp = crl->crlList;
95
96     CYASSL_ENTER("FreeCRL");
97
98     if (crl->monitors[0].path)
99         XFREE(crl->monitors[0].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
100
101     if (crl->monitors[1].path)
102         XFREE(crl->monitors[1].path, NULL, DYNAMIC_TYPE_CRL_MONITOR);
103
104     while(tmp) {
105         CRL_Entry* next = tmp->next;
106         FreeCRL_Entry(tmp);
107         XFREE(tmp, NULL, DYNAMIC_TYPE_CRL_ENTRY);
108         tmp = next;
109     }   
110
111 #ifdef HAVE_CRL_MONITOR
112     if (crl->tid != 0) {
113         CYASSL_MSG("Canceling monitor thread");
114         pthread_cancel(crl->tid);
115     }
116 #endif
117     FreeMutex(&crl->crlLock);
118 }
119
120
121 /* Is the cert ok with CRL, return 0 on success */
122 int CheckCertCRL(CYASSL_CRL* crl, DecodedCert* cert)
123 {
124     CRL_Entry* crle;
125     int        foundEntry = 0;
126     int        revoked = 0;
127     int        ret = 0;
128
129     CYASSL_ENTER("CheckCertCRL");
130
131     if (LockMutex(&crl->crlLock) != 0) {
132         CYASSL_MSG("LockMutex failed");
133         return BAD_MUTEX_ERROR;
134     }
135
136     crle = crl->crlList;
137
138     while (crle) {
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");
142
143             if (!ValidateDate(crle->nextDate, crle->nextDateFormat, AFTER)) {
144                 CYASSL_MSG("CRL next date is no longer valid");
145                 ret = ASN_AFTER_DATE_E;
146             }
147             else
148                 foundEntry = 1;
149             break;
150         }
151         crle = crle->next;
152     }
153
154     if (foundEntry) {
155         RevokedCert* rc = crle->certs;
156
157         while (rc) {
158             if (XMEMCMP(rc->serialNumber, cert->serial, rc->serialSz) == 0) {
159                 CYASSL_MSG("Cert revoked");
160                 revoked = 1;
161                 ret = CRL_CERT_REVOKED;
162                 break;
163             }
164             rc = rc->next;      
165         }
166     }
167
168     UnLockMutex(&crl->crlLock);
169
170     if (foundEntry == 0) {
171         CYASSL_MSG("Couldn't find CRL for status check");
172         ret = CRL_MISSING;
173         if (crl->cm->cbMissingCRL) {
174             char url[256];
175
176             CYASSL_MSG("Issuing missing CRL callback");
177             url[0] = '\0';
178             if (cert->extCrlInfoSz < (int)sizeof(url) -1 ) {
179                 XMEMCPY(url, cert->extCrlInfo, cert->extCrlInfoSz);
180                 url[cert->extCrlInfoSz] = '\0';
181             }
182             else  {
183                 CYASSL_MSG("CRL url too long");
184             }
185             crl->cm->cbMissingCRL(url);
186         }
187     }
188
189
190     return ret; 
191 }
192
193
194 /* Add Decoded CRL, 0 on success */
195 static int AddCRL(CYASSL_CRL* crl, DecodedCRL* dcrl)
196 {
197     CRL_Entry* crle;
198
199     CYASSL_ENTER("AddCRL");
200
201     crle = (CRL_Entry*)XMALLOC(sizeof(CRL_Entry), NULL, DYNAMIC_TYPE_CRL_ENTRY);
202     if (crle == NULL) {
203         CYASSL_MSG("alloc CRL Entry failed");
204         return -1;
205     }
206
207     if (InitCRL_Entry(crle, dcrl) < 0) {
208         CYASSL_MSG("Init CRL Entry failed");
209         XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
210         return -1;
211     }
212
213     if (LockMutex(&crl->crlLock) != 0) {
214         CYASSL_MSG("LockMutex failed");
215         FreeCRL_Entry(crle);
216         XFREE(crle, NULL, DYNAMIC_TYPE_CRL_ENTRY);
217         return BAD_MUTEX_ERROR;
218     }
219     crle->next = crl->crlList;
220     crl->crlList = crle;
221     UnLockMutex(&crl->crlLock);
222
223     return 0;
224 }
225
226
227 /* Load CRL File of type, SSL_SUCCESS on ok */
228 int BufferLoadCRL(CYASSL_CRL* crl, const byte* buff, long sz, int type)
229 {
230     int          ret = SSL_SUCCESS;
231     const byte*  myBuffer = buff;    /* if DER ok, otherwise switch */
232     buffer       der;
233     DecodedCRL   dcrl;
234
235     der.buffer = NULL;
236
237     CYASSL_ENTER("BufferLoadCRL");
238
239     if (crl == NULL || buff == NULL || sz == 0)
240         return BAD_FUNC_ARG;
241
242     if (type == SSL_FILETYPE_PEM) {
243         int eccKey = 0;   /* not used */
244         EncryptedInfo info;
245         info.ctx = NULL;
246
247         ret = PemToDer(buff, sz, CRL_TYPE, &der, NULL, &info, &eccKey);
248         if (ret == 0) {
249             myBuffer = der.buffer;
250             sz = der.length;
251         }
252         else {
253             CYASSL_MSG("Pem to Der failed");
254             return -1;
255         }
256     }
257
258     InitDecodedCRL(&dcrl);
259     ret = ParseCRL(&dcrl, myBuffer, sz, crl->cm);
260     if (ret != 0) {
261         CYASSL_MSG("ParseCRL error");
262     }
263     else {
264         ret = AddCRL(crl, &dcrl);
265         if (ret != 0) {
266             CYASSL_MSG("AddCRL error");
267         }
268     }
269     FreeDecodedCRL(&dcrl);
270
271     if (der.buffer)
272         XFREE(der.buffer, NULL, DYNAMIC_TYPE_CRL);
273
274     if (ret == 0)
275         return SSL_SUCCESS;  /* convert */
276     return ret;
277 }
278
279
280 #ifdef HAVE_CRL_MONITOR
281
282
283 /* read in new CRL entries and save new list */
284 static int SwapLists(CYASSL_CRL* crl)
285 {
286     int        ret;
287     CYASSL_CRL tmp;
288     CRL_Entry* newList;
289
290     if (InitCRL(&tmp, crl->cm) < 0) {
291         CYASSL_MSG("Init tmp CRL failed");
292         return -1;
293     }
294
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");
299             FreeCRL(&tmp);
300             return -1;
301         }
302     }
303
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");
308             FreeCRL(&tmp);
309             return -1;
310         }
311     }
312
313     if (LockMutex(&crl->crlLock) != 0) {
314         CYASSL_MSG("LockMutex failed");
315         FreeCRL(&tmp);
316         return -1;
317     }
318
319     newList = tmp.crlList;
320
321     /* swap lists */
322     tmp.crlList  = crl->crlList;
323     crl->crlList = newList;
324
325     UnLockMutex(&crl->crlLock);
326
327     FreeCRL(&tmp);
328
329     return 0;
330 }
331
332
333 #ifdef __MACH__
334
335 #include <sys/event.h>
336 #include <sys/time.h>
337 #include <fcntl.h>
338
339 /* OS X  monitoring */
340 static void* DoMonitor(void* arg)
341 {
342     int fPEM, fDER, kq;
343     struct kevent change;
344
345     CYASSL_CRL* crl = (CYASSL_CRL*)arg;
346
347     CYASSL_ENTER("DoMonitor");
348
349     kq = kqueue();
350     if (kq == -1) {
351         CYASSL_MSG("kqueue failed");
352         return NULL;
353     }
354
355     fPEM = -1;
356     fDER = -1;
357
358     if (crl->monitors[0].path) {
359         fPEM = open(crl->monitors[0].path, O_EVTONLY);
360         if (fPEM == -1) {
361             CYASSL_MSG("PEM event dir open failed");
362             return NULL;
363         }
364     }
365
366     if (crl->monitors[1].path) {
367         fDER = open(crl->monitors[1].path, O_EVTONLY);
368         if (fDER == -1) {
369             CYASSL_MSG("DER event dir open failed");
370             return NULL;
371         }
372     }
373
374     if (fPEM != -1)
375         EV_SET(&change, fPEM, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
376                 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
377
378     if (fDER != -1)
379         EV_SET(&change, fDER, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT,
380                 NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_ATTRIB, 0, 0);
381
382     for (;;) {
383         struct kevent event;
384         int           numEvents = kevent(kq, &change, 1, &event, 1, NULL);
385        
386         CYASSL_MSG("Got kevent");
387
388         if (numEvents == -1) {
389             CYASSL_MSG("kevent problem, continue");
390             continue;
391         }
392
393         if (SwapLists(crl) < 0) {
394             CYASSL_MSG("SwapLists problem, continue");
395         }
396     }
397
398     return NULL;
399 }
400
401
402 #elif __linux__
403
404 #include <sys/types.h>
405 #include <sys/inotify.h>
406 #include <unistd.h>
407
408 /* linux monitoring */
409 static void* DoMonitor(void* arg)
410 {
411     int         notifyFd;
412     int         wd;
413     CYASSL_CRL* crl = (CYASSL_CRL*)arg;
414
415     CYASSL_ENTER("DoMonitor");
416
417     notifyFd = inotify_init();
418     if (notifyFd < 0) {
419         CYASSL_MSG("inotify failed");
420         return NULL;
421     }
422
423     if (crl->monitors[0].path) {
424         wd = inotify_add_watch(notifyFd, crl->monitors[0].path, IN_CLOSE_WRITE |
425                                                                 IN_DELETE);
426         if (wd < 0) {
427             CYASSL_MSG("PEM notify add watch failed");
428             return NULL;
429         }
430     }
431
432     if (crl->monitors[1].path) {
433         wd = inotify_add_watch(notifyFd, crl->monitors[1].path, IN_CLOSE_WRITE |
434                                                                 IN_DELETE);
435         if (wd < 0) {
436             CYASSL_MSG("DER notify add watch failed");
437             return NULL;
438         }
439     }
440
441     for (;;) {
442         char          buffer[8192];
443         int           length = read(notifyFd, buffer, sizeof(buffer));
444        
445         CYASSL_MSG("Got notify event");
446
447         if (length < 0) {
448             CYASSL_MSG("notify read problem, continue");
449             continue;
450         } 
451
452         if (SwapLists(crl) < 0) {
453             CYASSL_MSG("SwapLists problem, continue");
454         }
455     }
456
457     return NULL;
458 }
459
460
461
462 #endif /* MACH or linux */
463
464
465 /* Start Monitoring the CRL path(s) in a thread */
466 static int StartMonitorCRL(CYASSL_CRL* crl)
467 {
468     pthread_attr_t attr;
469
470     CYASSL_ENTER("StartMonitorCRL");
471
472     if (crl == NULL) 
473         return BAD_FUNC_ARG;
474
475     if (crl->tid != 0) {
476         CYASSL_MSG("Monitor thread already running");
477         return MONITOR_RUNNING_E;
478     }
479
480     pthread_attr_init(&attr);
481
482     if (pthread_create(&crl->tid, &attr, DoMonitor, crl) != 0) {
483         CYASSL_MSG("Thread creation error");
484         return THREAD_CREATE_E;
485     }
486
487     return SSL_SUCCESS;
488 }
489
490
491 #else /* HAVE_CRL_MONITOR */
492
493 static int StartMonitorCRL(CYASSL_CRL* crl)
494 {
495     CYASSL_ENTER("StartMonitorCRL");
496     CYASSL_MSG("Not compiled in");
497
498     return NOT_COMPILED_IN;
499 }
500
501 #endif  /* HAVE_CRL_MONITOR */
502
503
504 /* Load CRL path files of type, SSL_SUCCESS on ok */ 
505 int LoadCRL(CYASSL_CRL* crl, const char* path, int type, int monitor)
506 {
507     struct dirent* entry;
508     DIR*   dir;
509     int    ret = SSL_SUCCESS;
510
511     CYASSL_ENTER("LoadCRL");
512     if (crl == NULL)
513         return BAD_FUNC_ARG;
514
515     dir = opendir(path);
516     if (dir == NULL) {
517         CYASSL_MSG("opendir path crl load failed");
518         return BAD_PATH_ERROR;
519     }
520     while ( (entry = readdir(dir)) != NULL) {
521         if (entry->d_type & DT_REG) {
522             char name[MAX_FILENAME_SZ];
523
524             if (type == SSL_FILETYPE_PEM) {
525                 if (strstr(entry->d_name, ".pem") == NULL) {
526                     CYASSL_MSG("not .pem file, skipping");
527                     continue;
528                 }
529             }
530             else {
531                 if (strstr(entry->d_name, ".der") == NULL &&
532                     strstr(entry->d_name, ".crl") == NULL) {
533
534                     CYASSL_MSG("not .der or .crl file, skipping");
535                     continue;
536                 }
537             }
538
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);
543
544             if (ProcessFile(NULL, name, type, CRL_TYPE, NULL, 0, crl)
545                                                                != SSL_SUCCESS) {
546                 CYASSL_MSG("CRL file load failed, continuing");
547             }
548         }
549     }
550
551     if (monitor & CYASSL_CRL_MONITOR) {
552         CYASSL_MSG("monitor path requested");
553
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)
558                 ret = MEMORY_E;
559         } else {
560             crl->monitors[1].path = strdup(path);
561             crl->monitors[1].type = SSL_FILETYPE_ASN1;
562             if (crl->monitors[1].path == NULL)
563                 ret = MEMORY_E;
564         }
565       
566         if (monitor & CYASSL_CRL_START_MON) {
567             CYASSL_MSG("start monitoring requested");
568     
569             ret = StartMonitorCRL(crl);
570        } 
571     }
572
573     return ret;
574 }
575
576 #endif /* HAVE_CRL */