source: libabac/abac_openssl.c @ 9ac7fb4

abac0-leakabac0-meimei-idmei-rt0-nmei_rt0tvf-new-xml
Last change on this file since 9ac7fb4 was 9ac7fb4, checked in by Mei <mei@…>, 11 years ago

1) work around some compilation warnings

  • Property mode set to 100644
File size: 17.9 KB
Line 
1
2/* abac_openssl.c */
3
4#define _GNU_SOURCE
5#include <stdio.h>
6#include <stdlib.h>
7#include <assert.h>
8#include <ctype.h>
9#include <unistd.h>
10
11#include <fcntl.h>
12#include <sys/types.h>
13#include <sys/stat.h>
14#include <sys/mman.h>
15#include <time.h>
16
17#include <stdbool.h>
18
19#include <openssl/conf.h>
20#include <openssl/x509.h>
21#include <openssl/x509v3.h>
22#include <openssl/x509_vfy.h>
23
24#include <openssl/rsa.h>
25#include <openssl/evp.h>
26#include <openssl/err.h>
27#include <openssl/pem.h>
28#include <openssl/ssl.h>
29#include <openssl/rand.h>
30
31
32#ifdef HAVE_READPASSPHRASE
33# include <readpassphrase.h>
34#else
35# include "compat/readpassphrase.h"
36#endif
37
38#define SHA1_LENGTH 40
39
40static int debug=0;
41
42int _potato_cb(char *buf, int sz, int rwflag, void *u);
43
44/***********************************************************************/
45int init_openssl() {
46    ERR_load_crypto_strings();
47    OpenSSL_add_all_algorithms();
48    return 0;
49}
50
51int deinit_openssl() {
52    CRYPTO_cleanup_all_ex_data();
53    return 0;
54}
55
56/* int RAND_bytes(unsigned char *buf, int num); */
57unsigned char *abac_generate_serial() {
58    unsigned char *serial=(unsigned char *) malloc(sizeof(unsigned char)*8);
59
60    memset(serial, '\0', 8);
61
62    if(!RAND_bytes(serial,8)) {
63        fprintf(stderr,"RAT, RAN^D out of seeds!!!\n");
64        assert(0);
65    }
66    // zap leading 0's
67    while (serial[0] == 0)
68        RAND_bytes(&serial[0],1);
69
70    RAND_cleanup();
71    return serial;
72}
73
74
75static BIGNUM *_make_bn_from_string(unsigned char *str)
76{
77    assert(str);
78    BIGNUM *tmp;
79    tmp=BN_bin2bn(str,8,NULL);
80/* BN_print_fp(stderr,tmp); */
81    int n=BN_num_bytes(tmp);
82    if(n) return tmp;
83        return NULL;
84}
85
86unsigned char *_encode_m64(unsigned char *orig_ptr, int orig_len)
87{
88    BIO *mbio,*b64bio,*bio;
89
90    unsigned char *m64_ptr=NULL;
91    int m64_len=0;
92
93    unsigned char *ptr=NULL;
94
95    if(orig_len==0) return NULL;
96
97    /*bio pointing at b64->mem, the base64 bio encodes on
98      write and decodes on read */
99    mbio=BIO_new(BIO_s_mem());
100    b64bio=BIO_new(BIO_f_base64());
101    bio=BIO_push(b64bio,mbio);
102
103    BIO_write(bio,orig_ptr,orig_len);
104
105    /* We need to 'flush' things to push out the encoding of the
106    * last few bytes.  There is special encoding if it is not a
107    * multiple of 3
108    */
109    BIO_flush(bio);
110
111    /* pointer to the data and the number of elements. */
112    m64_len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,ptr);
113
114    if(m64_len!=0) {
115       m64_ptr=malloc(m64_len+1);
116       if(m64_ptr) {
117           strcpy((char *)m64_ptr, (char *)ptr);
118           } else { 
119               fprintf(stderr,"ERROR: malloc failed\n");
120       }
121    }
122
123    /* This call will walk the chain freeing all the BIOs */
124    BIO_free_all(bio);
125    return m64_ptr;
126}
127
128unsigned char *_decode_m64(unsigned char *m64_ptr, int m64_len)
129{
130    unsigned char *orig_ptr=NULL;
131    int orig_len=0;
132
133    BIO *b64bio, *mbio, *bio;
134    char *ptr=NULL;
135
136    if(m64_len==0) return NULL;
137
138    ptr = (char *)malloc(sizeof(char)*m64_len);
139    memset(ptr, '\0', m64_len);
140
141    b64bio = BIO_new(BIO_f_base64());
142    mbio = BIO_new_mem_buf(m64_ptr, m64_len);
143    bio = BIO_push(b64bio, mbio);
144
145    orig_len=BIO_read(bio, ptr, m64_len);
146   
147    if(orig_len) {
148        orig_ptr=malloc(orig_len+1);
149        if(orig_ptr)
150            strcpy((char *)orig_ptr, ptr);
151            else fprintf(stderr,"ERROR: malloc failed..\n");
152    }
153
154    BIO_free_all(bio);
155    return orig_ptr;
156}
157
158/*** not used
159static char *_read_blob_from_file(char *fname, int *len)
160{
161    struct stat sb;
162    char *dptr=NULL;
163
164    int fd = open(fname, O_RDONLY);
165    if (fd == -1) { return NULL; }
166    if(stat(fname, &sb) == -1) {
167        close(fd);
168        return NULL;
169    }
170    dptr= (char *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
171    close(fd);
172
173    if(dptr == MAP_FAILED) {
174        return NULL;
175    }
176    *len=sb.st_size;
177    return dptr;
178}
179***/
180
181/* Read ID in PEM */
182X509 *abac_load_id_from_fp(FILE *fp)
183{
184    X509 *cert=PEM_read_X509(fp,NULL,NULL,NULL);
185
186    if (cert == NULL) {
187        ERR_print_errors_fp (stderr);
188        return NULL;
189    }
190    return cert;
191}
192
193X509 *abac_load_id_from_chunk(unsigned char *chunk_ptr, int chunk_len)
194{
195    X509 *n509=NULL;
196    BIO *mbio=BIO_new(BIO_s_mem());
197
198    BIO_write(mbio,chunk_ptr,chunk_len);
199    BIO_flush(mbio);
200
201    PEM_read_bio_X509(mbio,&n509,NULL,NULL);
202
203    BIO_free_all(mbio);
204
205    if (n509 == NULL) {
206        ERR_print_errors_fp (stderr);
207        return NULL;
208    }
209    return n509;
210}
211
212int abac_write_id_to_fp(X509 *cert, FILE *fp)
213{
214    assert(cert);
215
216    int ret=PEM_write_X509(fp,cert);
217
218    if (ret) {
219        ERR_print_errors_fp (stderr);
220        return ret;
221    }
222    return 0;
223}
224
225/* make stringfy a private key PEM struct */
226unsigned char *abac_string_privkey(EVP_PKEY *key)
227{
228    unsigned char *ptr=NULL;
229    unsigned char *tmp=NULL;
230
231    assert(key);
232
233    BIO *mbio=BIO_new(BIO_s_mem());
234    /* PEM_write_PrivateKey(fp,key,NULL,NULL,0,_potato_cb, "privateKey to file"); */
235    PEM_write_bio_PrivateKey(mbio,key,NULL,NULL,0,_potato_cb,"stringify privateKey");
236    BIO_flush(mbio);
237    int len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,tmp);
238
239    if(debug) fprintf(stderr,"CHUNKING PrivateKey... %d\n",len);
240
241    if(len) {
242        ptr=(unsigned char *)malloc(sizeof(unsigned char *)*(len+1));
243        int ret=BIO_read(mbio, (void *)ptr, len);
244        if(ret==0)
245            fprintf(stderr," abac_string_privkey failed!!\n");
246        ptr[len]='\0';
247    }
248    BIO_free_all(mbio);
249    return ptr;
250}
251
252/* make stringfy a x509 PEM struct */
253unsigned char *abac_string_cert(X509 *cert) {
254    unsigned char *ptr=NULL;
255    unsigned char *tmp=NULL;
256
257    assert(cert);
258
259    BIO *mbio=BIO_new(BIO_s_mem());
260    PEM_write_bio_X509(mbio,cert);
261    BIO_flush(mbio);
262    int len=(int)BIO_ctrl(mbio,BIO_CTRL_INFO,0,tmp);
263    if(debug) fprintf(stderr,"CHUNKING X509... %d\n",len);
264
265    if(len) {
266        ptr=(unsigned char *)malloc(sizeof(unsigned char *)*(len+1));
267        int ret=BIO_read(mbio, (void *)ptr, len);
268        if(ret==0)
269            fprintf(stderr," abac_string_cert failed!!\n");
270        ptr[len]='\0';
271    }
272   
273    BIO_free_all(mbio);
274    return ptr;
275}
276
277
278/* not used, sign data with privkey 
279static int _sign_with_privkey(EVP_PKEY *privkey, char *data,
280unsigned char* signed_buf)
281{
282  int err;
283  unsigned int signed_len;
284  EVP_MD_CTX     md_ctx;
285
286  EVP_SignInit   (&md_ctx, EVP_md5());
287  EVP_SignUpdate (&md_ctx, data, strlen(data));
288  signed_len = sizeof(signed_buf);
289  err = EVP_SignFinal (&md_ctx,
290                       signed_buf,
291                       &signed_len,
292                       privkey);
293  if (err != 1) {
294      ERR_print_errors_fp (stderr);
295      return 1;
296  }
297  return 0;
298}
299**/
300
301/* nost used, verify the signature..
302static int _verify_with_pubkey(EVP_PKEY *pubkey, char *data,
303unsigned char* signed_buf )
304{
305  int err;
306  int signed_len;
307  EVP_MD_CTX     md_ctx;
308
309  EVP_VerifyInit   (&md_ctx, EVP_sha1());
310  EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data));
311  signed_len=sizeof(signed_buf);
312  err = EVP_VerifyFinal (&md_ctx,
313                         signed_buf,
314                         signed_len,
315                         pubkey);
316
317  if (err != 1) {
318        ERR_print_errors_fp (stderr);
319        return 1;
320  }
321  fprintf(stderr, "Signature Verified Ok.\n");
322  return 0;
323}
324***/
325
326
327#define PWLEN 128
328/* EVP_PKEY *PEM_read_PrivateKey(FILE *,EVP_PKEY **,pem_cb *,void *) */
329int _potato_cb(char *buf, int sz, int rwflag, void *u)
330{
331   int len;
332   char *prompt=NULL;
333   if(u)
334       asprintf(&prompt,"Enter passphrase for %s:", (char *)u);
335       else asprintf(&prompt,"Enter passphrase :");
336   char *secret = malloc(PWLEN);
337   memset(secret, '\0', PWLEN);
338   if(!secret) {
339        perror("malloc()");
340        free(prompt);
341        return 0;
342   }
343   if (readpassphrase( prompt, secret, PWLEN, RPP_ECHO_OFF) == NULL) {
344       perror("readpassphrase()");
345       memset(secret, '\0', PWLEN);
346       len=0;
347       } else {
348           len=strlen(secret);
349           memcpy(buf, secret, len);
350           memset(secret, '\0', len);
351   }
352   free(secret);
353   free(prompt);
354   return len;
355}
356
357EVP_PKEY *abac_load_privkey_from_fp(FILE *fp)
358{
359    assert(fp);
360
361    EVP_PKEY *privkey = PEM_read_PrivateKey(fp, NULL, _potato_cb, "privateKey from file");
362
363    if (privkey == NULL) {
364        ERR_print_errors_fp (stderr);
365        return NULL;
366    }
367    return privkey;
368}
369
370/* not adding passphrase */
371int abac_write_privkey_to_fp(EVP_PKEY *key, FILE *fp) {
372    assert(key);
373
374    int ret=PEM_write_PrivateKey(fp,key,NULL,NULL,0,NULL, NULL);
375    if(ret) return ret;
376    return 0;
377}
378
379/* adding passphrase */
380int abac_write_encrypt_privkey_to_fp(EVP_PKEY *key, FILE *fp) {
381    assert(key);
382
383    int ret=PEM_write_PrivateKey(fp,key,NULL,NULL,0,_potato_cb, "privateKey to file");
384    if(ret) return ret;
385    return 0;
386}
387
388EVP_PKEY *extract_pubkey_from_cert(X509 *cert)
389{
390    EVP_PKEY *pubkey=X509_get_pubkey(cert);
391    return pubkey;
392}
393
394
395/** not used,
396static void _callback(int p, int n, void *arg)
397{
398    char c='B';
399
400    if (p == 0) c='.';
401    if (p == 1) c='+';
402    if (p == 2) c='*';
403    if (p == 3) c='\n';
404    fputc(c,stderr);
405}
406***/
407
408/*
409RSA *RSA_generate_key(int num, unsigned long e,
410   void (*callback)(int,int,void *), void *cb_arg);
411The exponent is an odd number, typically 3, 17 or 65537
412*/
413EVP_PKEY* abac_generate_key()
414{
415    EVP_PKEY *pk=NULL;
416    int keysize=2048;
417
418    if((pk=EVP_PKEY_new()) == NULL){
419        ERR_print_errors_fp (stderr);
420        return NULL;
421    }
422
423//    RSA *rsa=RSA_generate_key(keysize,RSA_F4,_callback,NULL);
424    RSA *rsa=RSA_generate_key(keysize,RSA_F4,NULL,NULL); 
425    if (!EVP_PKEY_assign_RSA(pk,rsa)) {
426        ERR_print_errors_fp (stderr);
427        return NULL;
428    }
429    rsa=NULL;
430
431    return pk;
432}
433
434/* Add extension using V3 code: we can set the config file as NULL
435 * because we wont reference any other sections.
436 */
437static int _add_ext(X509 *cert, int nid, char *value)
438{
439    X509_EXTENSION *ex;
440    X509V3_CTX ctx;
441    /* This sets the 'context' of the extensions. */
442    /* No configuration database */
443    X509V3_set_ctx_nodb(&ctx);
444    /* Issuer and subject certs: both the target since it is self signed,
445     * no request and no CRL
446     */
447    X509V3_set_ctx(&ctx, cert, cert, NULL, NULL, 0);
448    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
449    if (!ex)
450        return 0;
451
452    X509_add_ext(cert,ex,-1);
453    X509_EXTENSION_free(ex);
454    return 1;
455}
456
457
458/**
459 * Generate ID certificate.
460 *
461 * validity is measured in seconds (as of 0.2.0)
462 */
463X509 *abac_generate_cert(EVP_PKEY *pkey, char *cn, long validity) {
464
465    /* must have a privkey before generating an ID cert?? */
466    assert(pkey);
467    X509 *cert=NULL;
468
469    if((cert=X509_new()) == NULL)
470            goto error;
471
472    unsigned char *serial=abac_generate_serial();
473
474    if(validity == 0) validity=(long)(60*60*24*(365));
475
476    X509_set_version(cert,2);
477
478    BIGNUM *bn=_make_bn_from_string(serial);
479    BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert));
480    /* this is prone to problem with very big days on 32 bit machines,
481       In newer openssl, can migrate to X509_time_adj_ex */ 
482    X509_gmtime_adj(X509_get_notBefore(cert),0);
483    X509_gmtime_adj(X509_get_notAfter(cert),validity);
484    X509_set_pubkey(cert,pkey);
485
486    X509_NAME *name=X509_get_subject_name(cert);
487
488    if(!name) goto error;
489
490    /* This function creates and adds the entry, working out the
491     * correct string type and performing checks on its length.
492     */
493    if(!(X509_NAME_add_entry_by_txt(name,"CN", MBSTRING_ASC, (unsigned char *)cn, -1, -1, 0)))
494        goto error; // fail to add cn to cert
495
496    /* Self signed, set the issuer name to be the same as the subject. */
497    if(!(X509_set_issuer_name(cert,name)))
498        goto error; // fail to set issuer name on cert
499
500    /* Add various extensions: standard extensions */
501    if(!(_add_ext(cert, NID_basic_constraints, "critical,CA:TRUE")))
502        goto error; // fail to set basic constraint
503    if(!(_add_ext(cert, NID_key_usage, "critical,keyCertSign,cRLSign")))
504        goto error; // fail to set key usage
505    if(!(_add_ext(cert, NID_subject_key_identifier, "hash")))
506        goto error; // fail to set subject key identifier
507    if(!(_add_ext(cert, NID_authority_key_identifier, "keyid:always")))
508        goto error; // fail to set authority key identifier (self-signing)
509
510    /* make sure it is signed */
511    if (!X509_sign(cert,pkey,EVP_sha1()))
512        goto error;
513
514    return cert;
515
516error:
517    if(cert) X509_free(cert);
518    if(serial) free(serial);
519    if(bn) BN_free(bn);
520    return NULL;
521}
522
523/*** not used,
524static char *_time_in_string(ASN1_TIME *tm)
525{
526    char *ptr=NULL;
527    BIO *mbio=BIO_new(BIO_s_mem());
528    ASN1_TIME_print(mbio, tm);
529    BIO_flush(mbio);
530    int len=BIO_number_written(mbio);
531    ptr=(char *) malloc(sizeof(char *)*(len+1));
532    int ret=BIO_read(mbio, (void *)ptr, len);
533
534    BIO_free_all(mbio);
535    if(ret)
536        return ptr;
537        else return NULL;
538}
539***/
540
541
542/* atime->data, YYmmddHHMMSS or YYYYmmddHHMMSSZZ
543 *  V_ASN1_UTCTIME, V_ASN1_GENERALIZEDTIME
544 */
545static int _convert_time(struct tm *ttime, ASN1_TIME *atime) {
546    assert(atime); assert(atime->data);
547
548    int type=atime->type;
549    int len=strlen((char *)atime->data);
550    if(len==0) return 0;
551
552    char *astring=strndup((char *)atime->data,len);
553
554    /* setting ttime structure */
555    if (type == V_ASN1_UTCTIME) {
556           strptime(astring, "%y%m%d%H%M%S", ttime);
557        } else {
558        if (type == V_ASN1_GENERALIZEDTIME)
559           strptime(astring, "%Y%m%d%H%M%S", ttime);
560           else fprintf(stderr,"ERROR,.. unknown type in ASN1_TIME struct\n");
561    }
562
563    if(debug) {
564        char *tstring=asctime(ttime);
565        fprintf(stderr,"PPP final time string is %s\n",tstring);
566    }
567    return 1;
568}
569
570/* check whether the cert is still valid or not and also extract what its
571   not_before and not_after field */
572int abac_check_validity(X509 *cert, struct tm *not_before, struct tm *not_after) {
573    assert(cert);
574
575    int valid=0;
576    int ret=0;
577    memset(not_before, 0, sizeof(struct tm));
578    memset(not_after, 0, sizeof(struct tm));
579    ASN1_TIME *notAfter= X509_get_notAfter(cert);
580    ASN1_TIME *notBefore=X509_get_notBefore(cert);
581
582    ret=_convert_time(not_before, notBefore);
583    if(ret==0) return 0;
584    ret=_convert_time(not_after, notAfter);
585    if(ret==0) return 0;
586
587    if((X509_cmp_current_time(notBefore) >=0) ||
588                  (X509_cmp_current_time(notAfter) <=0) )
589      valid=1;
590
591    if(valid) return 0;
592       else return 1;
593}
594
595/* check if cert is still valid at current time, 1 for yes, 0 for no*/
596int abac_still_valid(X509 *cert)
597{
598    ASN1_TIME *notAfter= X509_get_notAfter(cert);
599    ASN1_TIME *notBefore=X509_get_notBefore(cert);
600    if(0) {
601        fprintf(stderr,"((X509_cmp_current_time(notBefore) is %d\n", 
602                                  X509_cmp_current_time(notBefore));
603        fprintf(stderr,"((X509_cmp_current_time(notAfter) is %d\n", 
604                                  X509_cmp_current_time(notAfter));
605    }
606    if((X509_cmp_current_time(notBefore) >=0) ||
607                   (X509_cmp_current_time(notAfter) <=0) )
608      return 0;
609    return 1;
610}
611
612int abac_self_signed(X509 *cert)
613{
614    int selfsigned=0;
615    X509_STORE *store=X509_STORE_new();
616    X509_STORE_CTX *ctx=X509_STORE_CTX_new();
617    /* Check selfsigned CA signature */
618    X509_STORE_set_flags(store,X509_V_FLAG_CHECK_SS_SIGNATURE);
619    X509_STORE_CTX_init(ctx,store,cert,NULL);
620    int ret=X509_verify_cert(ctx);
621    if(ret!=1) { /* 1 is okay, 0 or negative value are failures */
622        if(debug) fprintf(stderr,"error %d at %d depth lookup:%s\n",
623                ctx->error, ctx->error_depth, X509_verify_cert_error_string(ctx->error));
624        } else {
625            selfsigned=1;
626    }
627
628    X509_STORE_CTX_free(ctx);
629    X509_STORE_free(store);
630    return selfsigned;
631}
632
633int abac_signed_by(X509 *cert, X509 *root)
634{
635    int signedby=0;
636    X509_STORE *store=X509_STORE_new();
637    X509_STORE_add_cert(store,root);
638    X509_STORE_CTX *ctx=X509_STORE_CTX_new();
639    X509_STORE_CTX_init(ctx,store,cert,NULL);
640    int ret=X509_verify_cert(ctx);
641    if(ret!=1) { /* 1 is okay, 0 or negative value are failures */
642        if(debug) fprintf(stderr,"error %d at %d depth lookup:%s\n",
643                ctx->error, ctx->error_depth, X509_verify_cert_error_string(ctx->error));
644        } else {
645            signedby=1;
646    }
647
648    X509_STORE_CTX_free(ctx);
649    X509_STORE_free(store);
650    return signedby;
651}
652
653
654
655char *abac_get_cn(X509 *cert)
656{
657   X509_NAME *nptr=X509_get_subject_name (cert);
658   int pos=X509_NAME_get_index_by_NID(nptr, NID_commonName,-1);
659   X509_NAME_ENTRY *ent=X509_NAME_get_entry(nptr,pos); 
660   ASN1_STRING *adata=X509_NAME_ENTRY_get_data(ent);
661   unsigned char *val=ASN1_STRING_data(adata);
662   if(debug) fprintf(stderr," cn:(%d)(%s)\n", strlen((char *)val), val);
663   return (char *) val;
664}
665
666char *abac_get_serial(X509 *cert)
667{
668   char *ret=NULL;
669   ASN1_INTEGER *num=X509_get_serialNumber(cert);
670   BIGNUM *bnser=ASN1_INTEGER_to_BN(num,NULL);
671   int n=BN_num_bytes(bnser);
672   unsigned char buf[n];
673   int b=BN_bn2bin(bnser,buf);
674   if(debug) { 
675       fprintf(stderr," extract serial number:->(%d)",b);
676       BN_print_fp(stderr,bnser);
677   } 
678   if(n)
679       ret=strndup((char *)buf,n);
680   return ret;
681}
682
683char *abac_get_subject(X509 *cert) 
684{
685   char *ptr=X509_NAME_oneline(X509_get_subject_name(cert),0,0);
686   return ptr;
687}
688
689char *abac_get_issuer(X509 *cert) 
690{   
691   char *ptr=X509_NAME_oneline(X509_get_issuer_name(cert),0,0);
692   return ptr;
693}
694
695//  success: malloc'd copy with all hex digits lowercase
696//  fail: NULL
697unsigned char *abac_get_keyid(X509 *cert)
698{
699    ASN1_OCTET_STRING *ptr=X509_get_ext_d2i(cert,NID_subject_key_identifier,NULL,NULL);
700    char *str=i2s_ASN1_OCTET_STRING(NULL, ptr);
701    unsigned char *sha=(unsigned char *) malloc(sizeof(unsigned char)*SHA1_LENGTH+1);
702    memset(sha, '\0', SHA1_LENGTH);
703
704    int len=strlen(str);
705    int i=0;
706    int j=0;
707    for (j = 0; j < len; j++) {
708        if(str[j]==':')
709            continue;
710        sha[i] = tolower(str[j]);
711        if (!isxdigit(sha[i]))
712            goto error;
713        i++;
714        if(i>SHA1_LENGTH) 
715            goto error;
716    }
717    free(str);
718    sha[i]='\0';
719   
720    return sha;
721
722error:
723    free(str);
724    if(debug) fprintf(stderr,"SHA1 -> %s\n",sha);
725    free(sha);
726    return NULL;
727}
Note: See TracBrowser for help on using the repository browser.