auth_crypt.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (c) 2007 iptelorg GmbH
00005  *
00006  * This file is part of sip-router, a free SIP server.
00007  *
00008  * sip-router is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * sip-router is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00031 #define _GNU_SOURCE
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <openssl/pem.h>
00036 #include <openssl/err.h>
00037 #include <openssl/sha.h>
00038 #include <openssl/x509.h>
00039 #include <openssl/x509v3.h>
00040 
00041 #include "../../mem/mem.h"
00042 #include "../../parser/parse_uri.h"
00043 
00044 #include "auth_identity.h"
00045 
00046 
00047 
00048 int retrieve_x509(X509 **pcert, str *scert, int bacceptpem)
00049 {
00050         BIO *bcer=NULL;
00051         char serr[160];
00052         int iRet=0;
00053 
00054 
00055         if (!(bcer=BIO_new(BIO_s_mem()))) {
00056                 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: Unable to create BIO\n");
00057 
00058                 return -1;
00059         }
00060 
00061         do {
00062                 if (BIO_write(bcer, scert->s, scert->len)!=scert->len) {
00063                         LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: Unable to write BIO\n");
00064                         iRet=-2;
00065                         break;
00066                 }
00067 
00068                 /* RFC 4474 only accepts certs in the DER form but it can not harm
00069                  * to be a little bit more flexible and accept PEM as well. */
00070                 if (bacceptpem
00071                         && scert->len > BEGIN_PEM_CERT_LEN
00072                         && memmem(scert->s,
00073                                           scert->len,
00074                                           BEGIN_PEM_CERT,
00075                                           BEGIN_PEM_CERT_LEN)) {
00076                         if (!(*pcert = PEM_read_bio_X509(bcer, NULL, NULL, NULL))) {
00077                                 ERR_error_string_n(ERR_get_error(), serr, sizeof(serr));
00078                                 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: PEM Certificate %s\n", serr);
00079                                 iRet=-4;
00080                         }
00081                 } else {
00082                         if (!(*pcert = d2i_X509_bio(bcer, NULL))) {
00083                                 ERR_error_string_n(ERR_get_error(), serr, sizeof(serr));
00084                                 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: DER Certificate %s\n", serr);
00085                                 iRet=-3;
00086                         }
00087                 }
00088         } while (0);
00089 
00090         BIO_free(bcer);
00091 
00092         return iRet;
00093 }
00094 
00095 int check_x509_subj(X509 *pcert, str* sdom)
00096 {
00097         STACK_OF(GENERAL_NAME) *altnames;
00098         int ialts, i1, ilen, altlen;
00099         const GENERAL_NAME *actname;
00100         char scname[AUTH_DOMAIN_LENGTH];
00101         char *altptr;
00102         struct sip_uri suri;
00103         int ret = 0;
00104 
00105 
00106         /* we're looking for subjectAltName for the first time */
00107         altnames = X509_get_ext_d2i(pcert, NID_subject_alt_name, NULL, NULL);
00108 
00109         if (altnames) {
00110                 ialts = sk_GENERAL_NAME_num(altnames);
00111 
00112                 for (i1=0; i1 < ialts; i1++) {
00113                         actname = sk_GENERAL_NAME_value(altnames, i1);
00114 
00115                         if (actname->type == GEN_DNS || actname->type == GEN_URI) {
00116                                 /* we've found one */
00117                                 altptr = (char *)ASN1_STRING_data(actname->d.ia5);
00118                                 if (actname->type == GEN_URI) {
00119                                         if (parse_uri(altptr, strlen(altptr), &suri) != 0) {
00120                                                 continue;
00121                                         }
00122                                         if (!(suri.type == SIP_URI_T || suri.type == SIPS_URI_T)) {
00123                                                 continue;
00124                                         }
00125                                         if (suri.user.len != 0 || suri.passwd.len != 0) {
00126                                                 continue;
00127                                         }
00128                                         altptr = suri.host.s;
00129                                         altlen = suri.host.len;
00130                                 } else {
00131                                         altlen = strlen(altptr);
00132                                 }
00133                                 if (sdom->len != altlen 
00134                                         || strncasecmp(altptr, sdom->s, sdom->len)) {
00135                                         LOG(L_INFO, "AUTH_IDENTITY VERIFIER: subAltName of certificate doesn't match host name\n");
00136                                         ret = -1;
00137                                 } else {
00138                                         ret = 1;
00139                                         break;
00140                                 }
00141                         }
00142                 }
00143                 GENERAL_NAMES_free(altnames);
00144         }
00145 
00146         if (ret != 0) {
00147                 return ret == 1 ? 0 : ret;
00148         }
00149 
00150         /* certificate supplier host and certificate subject match check */
00151         ilen=X509_NAME_get_text_by_NID (X509_get_subject_name (pcert),
00152                                                                         NID_commonName,
00153                                                                         scname,
00154                                                                         sizeof (scname));
00155         if (sdom->len != ilen || strncasecmp(scname, sdom->s, sdom->len)) {
00156                 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: common name of certificate doesn't match host name\n");
00157                 return -2;
00158         }
00159 
00160         return 0;
00161 }
00162 
00163 int verify_x509(X509 *pcert, X509_STORE *pcacerts)
00164 {
00165         X509_STORE_CTX ca_ctx;
00166         char *strerr;
00167 
00168 
00169         if (X509_STORE_CTX_init(&ca_ctx, pcacerts, pcert, NULL) != 1) {
00170                 LOG(L_ERR, "AUTH_IDENTITY:verify_x509: Unable to init X509 store ctx\n");
00171                 return -1;
00172         }
00173 
00174         if (X509_verify_cert(&ca_ctx) != 1) {
00175                 strerr = (char *) X509_verify_cert_error_string(ca_ctx.error);
00176                 LOG(L_ERR, "AUTH_IDENTITY VERIFIER: Certificate verification error: %s\n", strerr);
00177                 X509_STORE_CTX_cleanup(&ca_ctx);
00178                 return -2;
00179         }
00180         X509_STORE_CTX_cleanup(&ca_ctx);
00181 
00182         LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Certificate is valid\n");
00183 
00184         return 0;
00185 }
00186 
00187 int rsa_sha1_enc (dynstr *sdigeststr,
00188                                   dynstr *senc,
00189                                   dynstr *sencb64,
00190                                   RSA *hmyprivkey)
00191 {
00192         unsigned char sstrcrypted[SHA_DIGEST_LENGTH];
00193         int ires;
00194         char serr[160];
00195 
00196 
00197         SHA1((unsigned char*)getstr_dynstr(sdigeststr).s,
00198                  getstr_dynstr(sdigeststr).len,
00199                  sstrcrypted);
00200 
00201 #ifdef NEW_RSA_PROC
00202         ires = senc->size;
00203         if (RSA_sign(NID_sha1,
00204                                  sstrcrypted,
00205                                  sizeof sstrcrypted,
00206                                  (unsigned char*)getstr_dynstr(senc).s,
00207                                  (unsigned int*)&ires,
00208                                  hmyprivkey) != 1) {
00209                 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
00210                 LOG(L_ERR, "AUTH_IDENTITY:rsa_sha1_enc: '%s'\n", serr);
00211                 return -2;
00212         }
00213 #else
00214         ires=RSA_private_encrypt(sizeof sstrcrypted, sstrcrypted,
00215                                                          (unsigned char*)getstr_dynstr(senc).s, hmyprivkey,
00216                                                          RSA_PKCS1_PADDING );
00217         if (ires<0)
00218         {
00219                 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
00220                 LOG(L_ERR, "AUTH_IDENTITY:rsa_sha1_enc: '%s'\n", serr);
00221                 return -1;
00222         }
00223 #endif
00224 
00225         base64encode(getstr_dynstr(senc).s, senc->size, getstr_dynstr(sencb64).s, &getstr_dynstr(sencb64).len );
00226 
00227         return 0;
00228 }
00229 
00230 int rsa_sha1_dec (char *sencedsha, int iencedshalen,
00231                                   char *ssha, int sshasize, int *ishalen,
00232                                   X509 *pcertx509)
00233 {
00234         EVP_PKEY *pkey;
00235         RSA* hpubkey;
00236         unsigned long lerr;
00237         char serr[160];
00238 
00239 
00240         pkey=X509_get_pubkey(pcertx509);
00241         if (pkey == NULL) {
00242                 lerr=ERR_get_error(); ERR_error_string_n(lerr, serr, sizeof(serr));
00243                 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Pubkey %s\n", serr);
00244                 return -1;
00245         }
00246 
00247         X509_free(pcertx509);
00248 
00249         hpubkey = EVP_PKEY_get1_RSA(pkey);
00250         EVP_PKEY_free(pkey);
00251         if (hpubkey == NULL) {
00252                 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Error getting RSA key\n");
00253                 return -2;
00254         }
00255 
00256 #ifdef NEW_RSA_PROC
00257         if (RSA_verify(NID_sha1,
00258                                         (unsigned char*)ssha, sshasize,
00259                                         (unsigned char*)sencedsha, iencedshalen,
00260                                         hpubkey) != 1) {
00261                 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: RSA verify returned: '%s'\n", ERR_error_string(ERR_get_error(), NULL));
00262                 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: RSA verify failed -> Invalid Identity Header\n");
00263                 RSA_free(hpubkey);
00264                 return -5;
00265         }
00266 #else
00267         /* it is bigger than the output buffer */
00268         if (RSA_size(hpubkey) > sshasize) {
00269                 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Unexpected Identity hash length (%d > %d)\n", RSA_size(hpubkey), sshasize);
00270                 RSA_free(hpubkey);
00271                 return -3;
00272         }
00273         *ishalen=RSA_public_decrypt(iencedshalen,
00274                                                                 (unsigned char*)sencedsha,
00275                                                                 (unsigned char*)ssha,
00276                                                                 hpubkey,
00277                                                                 RSA_PKCS1_PADDING);
00278         if (*ishalen<=0) {
00279                 lerr=ERR_get_error(); ERR_error_string_n(lerr, serr, sizeof(serr));
00280                 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: RSA operation error %s\n", serr);
00281                 RSA_free(hpubkey);
00282                 return -4;
00283         }
00284 #endif
00285 
00286         RSA_free(hpubkey);
00287 
00288         return 0;
00289 }
00290 
00291 /* copypasted from ser/modules/rr/avp_cookie.c + this adds '=' sign! ) */
00292 void base64encode(char* src_buf, int src_len, char* tgt_buf, int* tgt_len) {
00293         static char code64[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00294         int pos;
00295         for (pos=0, *tgt_len=0; pos < src_len; pos+=3,*tgt_len+=4) {
00296                 tgt_buf[*tgt_len+0] = code64[(unsigned char)src_buf[pos+0] >> 2];
00297                 tgt_buf[*tgt_len+1] = code64[(((unsigned char)src_buf[pos+0] & 0x03) << 4) | ((pos+1 < src_len)?((unsigned char)src_buf[pos+1] >> 4):0)];
00298                 if (pos+1 < src_len)
00299                         tgt_buf[*tgt_len+2] = code64[(((unsigned char)src_buf[pos+1] & 0x0F) << 2) | ((pos+2 < src_len)?((unsigned char)src_buf[pos+2] >> 6):0)];
00300                 else
00301                         tgt_buf[*tgt_len+2] = '=';
00302                 if (pos+2 < src_len)
00303                         tgt_buf[*tgt_len+3] = code64[(unsigned char)src_buf[pos+2] & 0x3F];
00304                 else
00305                         tgt_buf[*tgt_len+3] = '=';
00306         }
00307 }
00308 
00309 
00310 /* copypasted from ser/modules/rr/avp_cookie.c */
00311 void base64decode(char* src_buf, int src_len, char* tgt_buf, int* tgt_len) {
00312         int pos, i, n;
00313         unsigned char c[4];
00314         for (pos=0, i=0, *tgt_len=0; pos < src_len; pos++) {
00315                 if (src_buf[pos] >= 'A' && src_buf[pos] <= 'Z')
00316                         c[i] = src_buf[pos] - 65;   /* <65..90>  --> <0..25> */
00317                 else if (src_buf[pos] >= 'a' && src_buf[pos] <= 'z')
00318                         c[i] = src_buf[pos] - 71;   /* <97..122>  --> <26..51> */
00319                 else if (src_buf[pos] >= '0' && src_buf[pos] <= '9')
00320                         c[i] = src_buf[pos] + 4;    /* <48..56>  --> <52..61> */
00321                 else if (src_buf[pos] == '+')
00322                         c[i] = 62;
00323                 else if (src_buf[pos] == '/')
00324                         c[i] = 63;
00325                 else  /* '=' */
00326                         c[i] = 64;
00327                 i++;
00328                 if (pos == src_len-1) {
00329                         while (i < 4) {
00330                                 c[i] = 64;
00331                                 i++;
00332                         }
00333                 }
00334                 if (i==4) {
00335                         if (c[0] == 64)
00336                                 n = 0;
00337                         else if (c[2] == 64)
00338                                 n = 1;
00339                         else if (c[3] == 64)
00340                                 n = 2;
00341                         else
00342                                 n = 3;
00343                         switch (n) {
00344                                 case 3:
00345                                         tgt_buf[*tgt_len+2] = (char) (((c[2] & 0x03) << 6) | c[3]);
00346                                         /* no break */
00347                                 case 2:
00348                                         tgt_buf[*tgt_len+1] = (char) (((c[1] & 0x0F) << 4) | (c[2] >> 2));
00349                                         /* no break */
00350                                 case 1:
00351                                         tgt_buf[*tgt_len+0] = (char) ((c[0] << 2) | (c[1] >> 4));
00352                                         break;
00353                         }
00354                         i=0;
00355                         *tgt_len+= n;
00356                 }
00357         }
00358 }
00359 
00360 int x509_get_validitytime(time_t *tout, ASN1_UTCTIME *tin)
00361 {
00362         char *sasn1;
00363         int i1;
00364         struct tm tmptm;
00365 
00366 
00367         memset(&tmptm, 0, sizeof(tmptm));
00368         i1=tin->length;
00369         sasn1=(char *)tin->data;
00370 
00371         if (i1 < 10)
00372                 return -1;
00373 /*      if (sasn1[i1-1]!='Z')
00374                 return -1;*/
00375         for (i1=0; i1<10; i1++)
00376                 if((sasn1[i1] > '9') || (sasn1[i1] < '0'))
00377                         return -2;
00378 
00379         tmptm.tm_year=(sasn1[0]-'0')*10+(sasn1[1]-'0');
00380         if(tmptm.tm_year < 50)
00381                 tmptm.tm_year+=100;
00382 
00383         tmptm.tm_mon=(sasn1[2]-'0')*10+(sasn1[3]-'0')-1;
00384         if((tmptm.tm_mon > 11) || (tmptm.tm_mon < 0))
00385                 return -3;
00386 
00387         tmptm.tm_mday=(sasn1[4]-'0')*10+(sasn1[5]-'0');
00388         tmptm.tm_hour= (sasn1[6]-'0')*10+(sasn1[7]-'0');
00389         tmptm.tm_min=(sasn1[8]-'0')*10+(sasn1[9]-'0');
00390 
00391         if ((sasn1[10] >= '0') && (sasn1[10] <= '9') &&
00392                    (sasn1[11] >= '0') && (sasn1[11] <= '9'))
00393                 tmptm.tm_sec=(sasn1[10]-'0')*10+(sasn1[11]-'0');
00394 
00395 #ifdef HAVE_TIMEGM
00396         *tout=timegm(&tmptm);
00397 #else
00398         *tout=_timegm(&tmptm);
00399 #endif
00400 
00401         return 0;
00402 }
00403 
00404 int x509_get_notbefore(time_t *tout, X509 *pcert)
00405 {
00406         return (x509_get_validitytime(tout, X509_get_notBefore(pcert)));
00407 }
00408 
00409 int x509_get_notafter(time_t *tout, X509 *pcert)
00410 {
00411         return (x509_get_validitytime(tout, X509_get_notAfter(pcert)));
00412 }