1 /*
2 * Copyright (c) 2007 iptelorg GmbH
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /*!
22 * \file
23 * \brief Kamailio auth-identity :: Crypt
24 * \ingroup auth-identity
25 * Module: \ref auth-identity
26 */
27
28
29 #define _GNU_SOURCE
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <openssl/pem.h>
34 #include <openssl/err.h>
35 #include <openssl/sha.h>
36 #include <openssl/x509.h>
37 #include <openssl/x509v3.h>
38 #include <openssl/crypto.h>
39 #include <openssl/x509_vfy.h>
40
41 #include "../../core/mem/mem.h"
42 #include "../../core/parser/parse_uri.h"
43
44 #include "auth_identity.h"
45
46
47
retrieve_x509(X509 ** pcert,str * scert,int bacceptpem)48 int retrieve_x509(X509 **pcert, str *scert, int bacceptpem)
49 {
50 BIO *bcer=NULL;
51 char serr[160];
52 int iRet=0;
53
54
55 if (!(bcer=BIO_new(BIO_s_mem()))) {
56 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: Unable to create BIO\n");
57
58 return -1;
59 }
60
61 do {
62 if (BIO_write(bcer, scert->s, scert->len)!=scert->len) {
63 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: Unable to write BIO\n");
64 iRet=-2;
65 break;
66 }
67
68 /* RFC 4474 only accepts certs in the DER form but it can not harm
69 * to be a little bit more flexible and accept PEM as well. */
70 if (bacceptpem
71 && scert->len > BEGIN_PEM_CERT_LEN
72 && memmem(scert->s,
73 scert->len,
74 BEGIN_PEM_CERT,
75 BEGIN_PEM_CERT_LEN)) {
76 if (!(*pcert = PEM_read_bio_X509(bcer, NULL, NULL, NULL))) {
77 ERR_error_string_n(ERR_get_error(), serr, sizeof(serr));
78 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: PEM Certificate %s\n", serr);
79 iRet=-4;
80 }
81 } else {
82 if (!(*pcert = d2i_X509_bio(bcer, NULL))) {
83 ERR_error_string_n(ERR_get_error(), serr, sizeof(serr));
84 LOG(L_ERR, "AUTH_IDENTITY:retrieve_x509: DER Certificate %s\n", serr);
85 iRet=-3;
86 }
87 }
88 } while (0);
89
90 BIO_free(bcer);
91
92 return iRet;
93 }
94
check_x509_subj(X509 * pcert,str * sdom)95 int check_x509_subj(X509 *pcert, str* sdom)
96 {
97 STACK_OF(GENERAL_NAME) *altnames;
98 int ialts, i1, ilen, altlen;
99 const GENERAL_NAME *actname;
100 char scname[AUTH_DOMAIN_LENGTH];
101 char *altptr;
102 struct sip_uri suri;
103 int ret = 0;
104
105
106 /* we're looking for subjectAltName for the first time */
107 altnames = X509_get_ext_d2i(pcert, NID_subject_alt_name, NULL, NULL);
108
109 if (altnames) {
110 ialts = sk_GENERAL_NAME_num(altnames);
111
112 for (i1=0; i1 < ialts; i1++) {
113 actname = sk_GENERAL_NAME_value(altnames, i1);
114
115 if (actname->type == GEN_DNS || actname->type == GEN_URI) {
116 /* we've found one */
117 #if OPENSSL_VERSION_NUMBER >= 0x010100000L
118 altptr = (char *)ASN1_STRING_get0_data(actname->d.ia5);
119 #else
120 altptr = (char *)ASN1_STRING_data(actname->d.ia5);
121 #endif
122 if (actname->type == GEN_URI) {
123 if (parse_uri(altptr, strlen(altptr), &suri) != 0) {
124 continue;
125 }
126 if (!(suri.type == SIP_URI_T || suri.type == SIPS_URI_T)) {
127 continue;
128 }
129 if (suri.user.len != 0 || suri.passwd.len != 0) {
130 continue;
131 }
132 altptr = suri.host.s;
133 altlen = suri.host.len;
134 } else {
135 altlen = strlen(altptr);
136 }
137 if (sdom->len != altlen
138 || strncasecmp(altptr, sdom->s, sdom->len)) {
139 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: subAltName of certificate doesn't match host name\n");
140 ret = -1;
141 } else {
142 ret = 1;
143 break;
144 }
145 }
146 }
147 GENERAL_NAMES_free(altnames);
148 }
149
150 if (ret != 0) {
151 return ret == 1 ? 0 : ret;
152 }
153
154 /* certificate supplier host and certificate subject match check */
155 ilen=X509_NAME_get_text_by_NID (X509_get_subject_name (pcert),
156 NID_commonName,
157 scname,
158 sizeof (scname));
159 if (sdom->len != ilen || strncasecmp(scname, sdom->s, sdom->len)) {
160 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: common name of certificate doesn't match host name\n");
161 return -2;
162 }
163
164 return 0;
165 }
166
verify_x509(X509 * pcert,X509_STORE * pcacerts)167 int verify_x509(X509 *pcert, X509_STORE *pcacerts)
168 {
169 X509_STORE_CTX *ca_ctx = NULL;
170 char *strerr;
171
172 ca_ctx = X509_STORE_CTX_new();
173 if(ca_ctx==NULL) {
174 LM_ERR("cannot get a x509 context\n");
175 return -1;
176 }
177
178 if (X509_STORE_CTX_init(ca_ctx, pcacerts, pcert, NULL) != 1) {
179 LOG(L_ERR, "AUTH_IDENTITY:verify_x509: Unable to init X509 store ctx\n");
180 X509_STORE_CTX_free(ca_ctx);
181 return -1;
182 }
183
184 if (X509_verify_cert(ca_ctx) != 1) {
185 strerr = (char *)X509_verify_cert_error_string(X509_STORE_CTX_get_error(ca_ctx));
186 LOG(L_ERR, "AUTH_IDENTITY VERIFIER: Certificate verification error: %s\n", strerr);
187 X509_STORE_CTX_cleanup(ca_ctx);
188 X509_STORE_CTX_free(ca_ctx);
189 return -2;
190 }
191 X509_STORE_CTX_cleanup(ca_ctx);
192 X509_STORE_CTX_free(ca_ctx);
193
194 LOG(AUTH_DBG_LEVEL, "AUTH_IDENTITY VERIFIER: Certificate is valid\n");
195
196 return 0;
197 }
198
rsa_sha1_enc(dynstr * sdigeststr,dynstr * senc,dynstr * sencb64,RSA * hmyprivkey)199 int rsa_sha1_enc (dynstr *sdigeststr,
200 dynstr *senc,
201 dynstr *sencb64,
202 RSA *hmyprivkey)
203 {
204 unsigned char sstrcrypted[SHA_DIGEST_LENGTH];
205 int ires;
206 char serr[160];
207
208
209 SHA1((unsigned char*)getstr_dynstr(sdigeststr).s,
210 getstr_dynstr(sdigeststr).len,
211 sstrcrypted);
212
213 #ifdef NEW_RSA_PROC
214 ires = senc->size;
215 if (RSA_sign(NID_sha1,
216 sstrcrypted,
217 sizeof sstrcrypted,
218 (unsigned char*)getstr_dynstr(senc).s,
219 (unsigned int*)&ires,
220 hmyprivkey) != 1) {
221 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
222 LOG(L_ERR, "AUTH_IDENTITY:rsa_sha1_enc: '%s'\n", serr);
223 return -2;
224 }
225 #else
226 ires=RSA_private_encrypt(sizeof sstrcrypted, sstrcrypted,
227 (unsigned char*)getstr_dynstr(senc).s, hmyprivkey,
228 RSA_PKCS1_PADDING );
229 if (ires<0)
230 {
231 ERR_error_string_n(ERR_get_error(), serr, sizeof serr);
232 LOG(L_ERR, "AUTH_IDENTITY:rsa_sha1_enc: '%s'\n", serr);
233 return -1;
234 }
235 #endif
236
237 base64encode(getstr_dynstr(senc).s, senc->size, getstr_dynstr(sencb64).s, &getstr_dynstr(sencb64).len );
238
239 return 0;
240 }
241
rsa_sha1_dec(char * sencedsha,int iencedshalen,char * ssha,int sshasize,int * ishalen,X509 * pcertx509)242 int rsa_sha1_dec (char *sencedsha, int iencedshalen,
243 char *ssha, int sshasize, int *ishalen,
244 X509 *pcertx509)
245 {
246 EVP_PKEY *pkey;
247 RSA* hpubkey;
248 unsigned long lerr;
249 char serr[160];
250
251
252 pkey=X509_get_pubkey(pcertx509);
253 if (pkey == NULL) {
254 lerr=ERR_get_error(); ERR_error_string_n(lerr, serr, sizeof(serr));
255 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Pubkey %s\n", serr);
256 return -1;
257 }
258
259 X509_free(pcertx509);
260
261 hpubkey = EVP_PKEY_get1_RSA(pkey);
262 EVP_PKEY_free(pkey);
263 if (hpubkey == NULL) {
264 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Error getting RSA key\n");
265 return -2;
266 }
267
268 #ifdef NEW_RSA_PROC
269 if (RSA_verify(NID_sha1,
270 (unsigned char*)ssha, sshasize,
271 (unsigned char*)sencedsha, iencedshalen,
272 hpubkey) != 1) {
273 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: RSA verify returned: '%s'\n", ERR_error_string(ERR_get_error(), NULL));
274 LOG(L_INFO, "AUTH_IDENTITY VERIFIER: RSA verify failed -> Invalid Identity Header\n");
275 RSA_free(hpubkey);
276 return -5;
277 }
278 #else
279 /* it is bigger than the output buffer */
280 if (RSA_size(hpubkey) > sshasize) {
281 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: Unexpected Identity hash length (%d > %d)\n", RSA_size(hpubkey), sshasize);
282 RSA_free(hpubkey);
283 return -3;
284 }
285 *ishalen=RSA_public_decrypt(iencedshalen,
286 (unsigned char*)sencedsha,
287 (unsigned char*)ssha,
288 hpubkey,
289 RSA_PKCS1_PADDING);
290 if (*ishalen<=0) {
291 lerr=ERR_get_error(); ERR_error_string_n(lerr, serr, sizeof(serr));
292 LOG(L_ERR, "AUTH_IDENTITY:decrypt_identity: RSA operation error %s\n", serr);
293 RSA_free(hpubkey);
294 return -4;
295 }
296 #endif
297
298 RSA_free(hpubkey);
299
300 return 0;
301 }
302
303 /* copypasted from ser/modules/rr/avp_cookie.c + this adds '=' sign! ) */
base64encode(char * src_buf,int src_len,char * tgt_buf,int * tgt_len)304 void base64encode(char* src_buf, int src_len, char* tgt_buf, int* tgt_len) {
305 static char code64[64+1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
306 int pos;
307 for (pos=0, *tgt_len=0; pos < src_len; pos+=3,*tgt_len+=4) {
308 tgt_buf[*tgt_len+0] = code64[(unsigned char)src_buf[pos+0] >> 2];
309 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)];
310 if (pos+1 < src_len)
311 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)];
312 else
313 tgt_buf[*tgt_len+2] = '=';
314 if (pos+2 < src_len)
315 tgt_buf[*tgt_len+3] = code64[(unsigned char)src_buf[pos+2] & 0x3F];
316 else
317 tgt_buf[*tgt_len+3] = '=';
318 }
319 }
320
321
322 /* copypasted from ser/modules/rr/avp_cookie.c */
base64decode(char * src_buf,int src_len,char * tgt_buf,int * tgt_len)323 void base64decode(char* src_buf, int src_len, char* tgt_buf, int* tgt_len) {
324 int pos, i, n;
325 unsigned char c[4];
326 for (pos=0, i=0, *tgt_len=0; pos < src_len; pos++) {
327 if (src_buf[pos] >= 'A' && src_buf[pos] <= 'Z')
328 c[i] = src_buf[pos] - 65; /* <65..90> --> <0..25> */
329 else if (src_buf[pos] >= 'a' && src_buf[pos] <= 'z')
330 c[i] = src_buf[pos] - 71; /* <97..122> --> <26..51> */
331 else if (src_buf[pos] >= '0' && src_buf[pos] <= '9')
332 c[i] = src_buf[pos] + 4; /* <48..56> --> <52..61> */
333 else if (src_buf[pos] == '+')
334 c[i] = 62;
335 else if (src_buf[pos] == '/')
336 c[i] = 63;
337 else /* '=' */
338 c[i] = 64;
339 i++;
340 if (pos == src_len-1) {
341 while (i < 4) {
342 c[i] = 64;
343 i++;
344 }
345 }
346 if (i==4) {
347 if (c[0] == 64)
348 n = 0;
349 else if (c[2] == 64)
350 n = 1;
351 else if (c[3] == 64)
352 n = 2;
353 else
354 n = 3;
355 switch (n) {
356 case 3:
357 tgt_buf[*tgt_len+2] = (char) (((c[2] & 0x03) << 6) | c[3]);
358 /* no break */
359 case 2:
360 tgt_buf[*tgt_len+1] = (char) (((c[1] & 0x0F) << 4) | (c[2] >> 2));
361 /* no break */
362 case 1:
363 tgt_buf[*tgt_len+0] = (char) ((c[0] << 2) | (c[1] >> 4));
364 break;
365 }
366 i=0;
367 *tgt_len+= n;
368 }
369 }
370 }
371
x509_get_validitytime(time_t * tout,ASN1_UTCTIME * tin)372 int x509_get_validitytime(time_t *tout, ASN1_UTCTIME *tin)
373 {
374 char *sasn1;
375 int i1;
376 struct tm tmptm;
377
378
379 memset(&tmptm, 0, sizeof(tmptm));
380 i1=tin->length;
381 sasn1=(char *)tin->data;
382
383 if (i1 < 10)
384 return -1;
385 /* if (sasn1[i1-1]!='Z')
386 return -1;*/
387 for (i1=0; i1<10; i1++)
388 if((sasn1[i1] > '9') || (sasn1[i1] < '0'))
389 return -2;
390
391 tmptm.tm_year=(sasn1[0]-'0')*10+(sasn1[1]-'0');
392 if(tmptm.tm_year < 50)
393 tmptm.tm_year+=100;
394
395 tmptm.tm_mon=(sasn1[2]-'0')*10+(sasn1[3]-'0')-1;
396 if((tmptm.tm_mon > 11) || (tmptm.tm_mon < 0))
397 return -3;
398
399 tmptm.tm_mday=(sasn1[4]-'0')*10+(sasn1[5]-'0');
400 tmptm.tm_hour= (sasn1[6]-'0')*10+(sasn1[7]-'0');
401 tmptm.tm_min=(sasn1[8]-'0')*10+(sasn1[9]-'0');
402
403 if ((sasn1[10] >= '0') && (sasn1[10] <= '9') &&
404 (sasn1[11] >= '0') && (sasn1[11] <= '9'))
405 tmptm.tm_sec=(sasn1[10]-'0')*10+(sasn1[11]-'0');
406
407 #ifdef HAVE_TIMEGM
408 *tout=timegm(&tmptm);
409 #else
410 *tout=_timegm(&tmptm);
411 #endif
412
413 return 0;
414 }
415
x509_get_notbefore(time_t * tout,X509 * pcert)416 int x509_get_notbefore(time_t *tout, X509 *pcert)
417 {
418 return (x509_get_validitytime(tout, X509_get_notBefore(pcert)));
419 }
420
x509_get_notafter(time_t * tout,X509 * pcert)421 int x509_get_notafter(time_t *tout, X509 *pcert)
422 {
423 return (x509_get_validitytime(tout, X509_get_notAfter(pcert)));
424 }
425