source: libabac/abac_openssl.c @ 2e92c62

abac0-leak
Last change on this file since 2e92c62 was 2e92c62, checked in by Mei <mei@…>, 10 years ago

1) take out debug statement and fix SSL_keyid.c's compiler warning

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