1*5b0945b5SGregory Neil Shapiro /* 2*5b0945b5SGregory Neil Shapiro * Copyright (c) 2015 Proofpoint, Inc. and its suppliers. 3*5b0945b5SGregory Neil Shapiro * All rights reserved. 4*5b0945b5SGregory Neil Shapiro * 5*5b0945b5SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 6*5b0945b5SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 7*5b0945b5SGregory Neil Shapiro * the sendmail distribution. 8*5b0945b5SGregory Neil Shapiro * 9*5b0945b5SGregory Neil Shapiro */ 10*5b0945b5SGregory Neil Shapiro 11*5b0945b5SGregory Neil Shapiro #include <sendmail.h> 12*5b0945b5SGregory Neil Shapiro 13*5b0945b5SGregory Neil Shapiro SM_RCSID("@(#)$Id: tls.c,v 8.127 2013-11-27 02:51:11 gshapiro Exp $") 14*5b0945b5SGregory Neil Shapiro 15*5b0945b5SGregory Neil Shapiro #if STARTTLS 16*5b0945b5SGregory Neil Shapiro # include <tls.h> 17*5b0945b5SGregory Neil Shapiro 18*5b0945b5SGregory Neil Shapiro /* 19*5b0945b5SGregory Neil Shapiro ** DATA2HEX -- create a printable hex string from binary data ("%02X:") 20*5b0945b5SGregory Neil Shapiro ** 21*5b0945b5SGregory Neil Shapiro ** Parameters: 22*5b0945b5SGregory Neil Shapiro ** buf -- data 23*5b0945b5SGregory Neil Shapiro ** len -- length of data 24*5b0945b5SGregory Neil Shapiro ** hex -- output buffer 25*5b0945b5SGregory Neil Shapiro ** hlen -- length of output buffer 26*5b0945b5SGregory Neil Shapiro ** 27*5b0945b5SGregory Neil Shapiro ** Returns: 28*5b0945b5SGregory Neil Shapiro ** <0: errno 29*5b0945b5SGregory Neil Shapiro ** >0: length of data in hex 30*5b0945b5SGregory Neil Shapiro */ 31*5b0945b5SGregory Neil Shapiro 32*5b0945b5SGregory Neil Shapiro int 33*5b0945b5SGregory Neil Shapiro data2hex(buf, blen, hex, hlen) 34*5b0945b5SGregory Neil Shapiro unsigned char *buf; 35*5b0945b5SGregory Neil Shapiro int blen; 36*5b0945b5SGregory Neil Shapiro unsigned char *hex; 37*5b0945b5SGregory Neil Shapiro int hlen; 38*5b0945b5SGregory Neil Shapiro { 39*5b0945b5SGregory Neil Shapiro int r, h; 40*5b0945b5SGregory Neil Shapiro static const char hexcodes[] = "0123456789ABCDEF"; 41*5b0945b5SGregory Neil Shapiro 42*5b0945b5SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 43*5b0945b5SGregory Neil Shapiro SM_REQUIRE(hex != NULL); 44*5b0945b5SGregory Neil Shapiro if (blen * 3 + 2 > hlen) 45*5b0945b5SGregory Neil Shapiro return -ERANGE; 46*5b0945b5SGregory Neil Shapiro 47*5b0945b5SGregory Neil Shapiro for (r = 0, h = 0; r < blen && h + 3 < hlen; r++) 48*5b0945b5SGregory Neil Shapiro { 49*5b0945b5SGregory Neil Shapiro hex[h++] = hexcodes[(buf[r] & 0xf0) >> 4]; 50*5b0945b5SGregory Neil Shapiro hex[h++] = hexcodes[(buf[r] & 0x0f)]; 51*5b0945b5SGregory Neil Shapiro if (r + 1 < blen) 52*5b0945b5SGregory Neil Shapiro hex[h++] = ':'; 53*5b0945b5SGregory Neil Shapiro } 54*5b0945b5SGregory Neil Shapiro if (h >= hlen) 55*5b0945b5SGregory Neil Shapiro return -ERANGE; 56*5b0945b5SGregory Neil Shapiro hex[h] = '\0'; 57*5b0945b5SGregory Neil Shapiro return h; 58*5b0945b5SGregory Neil Shapiro } 59*5b0945b5SGregory Neil Shapiro 60*5b0945b5SGregory Neil Shapiro /* 61*5b0945b5SGregory Neil Shapiro ** TLS_DATA_MD -- calculate MD for data 62*5b0945b5SGregory Neil Shapiro ** 63*5b0945b5SGregory Neil Shapiro ** Parameters: 64*5b0945b5SGregory Neil Shapiro ** buf -- data (in and out!) 65*5b0945b5SGregory Neil Shapiro ** len -- length of data 66*5b0945b5SGregory Neil Shapiro ** md -- digest algorithm 67*5b0945b5SGregory Neil Shapiro ** 68*5b0945b5SGregory Neil Shapiro ** Returns: 69*5b0945b5SGregory Neil Shapiro ** <=0: cert fp calculation failed 70*5b0945b5SGregory Neil Shapiro ** >0: len of fp 71*5b0945b5SGregory Neil Shapiro ** 72*5b0945b5SGregory Neil Shapiro ** Side Effects: 73*5b0945b5SGregory Neil Shapiro ** writes digest to buf 74*5b0945b5SGregory Neil Shapiro */ 75*5b0945b5SGregory Neil Shapiro 76*5b0945b5SGregory Neil Shapiro static int 77*5b0945b5SGregory Neil Shapiro tls_data_md(buf, len, md) 78*5b0945b5SGregory Neil Shapiro unsigned char *buf; 79*5b0945b5SGregory Neil Shapiro int len; 80*5b0945b5SGregory Neil Shapiro const EVP_MD *md; 81*5b0945b5SGregory Neil Shapiro { 82*5b0945b5SGregory Neil Shapiro unsigned int md_len; 83*5b0945b5SGregory Neil Shapiro EVP_MD_CTX *mdctx; 84*5b0945b5SGregory Neil Shapiro unsigned char md_buf[EVP_MAX_MD_SIZE]; 85*5b0945b5SGregory Neil Shapiro 86*5b0945b5SGregory Neil Shapiro SM_REQUIRE(buf != NULL); 87*5b0945b5SGregory Neil Shapiro SM_REQUIRE(md != NULL); 88*5b0945b5SGregory Neil Shapiro SM_REQUIRE(len >= EVP_MAX_MD_SIZE); 89*5b0945b5SGregory Neil Shapiro 90*5b0945b5SGregory Neil Shapiro mdctx = EVP_MD_CTX_create(); 91*5b0945b5SGregory Neil Shapiro if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) 92*5b0945b5SGregory Neil Shapiro return -EINVAL; 93*5b0945b5SGregory Neil Shapiro if (EVP_DigestUpdate(mdctx, (void *)buf, len) != 1) 94*5b0945b5SGregory Neil Shapiro return -EINVAL; 95*5b0945b5SGregory Neil Shapiro if (EVP_DigestFinal_ex(mdctx, md_buf, &md_len) != 1) 96*5b0945b5SGregory Neil Shapiro return -EINVAL; 97*5b0945b5SGregory Neil Shapiro EVP_MD_CTX_destroy(mdctx); 98*5b0945b5SGregory Neil Shapiro 99*5b0945b5SGregory Neil Shapiro if (md_len > len) 100*5b0945b5SGregory Neil Shapiro return -ERANGE; 101*5b0945b5SGregory Neil Shapiro (void) memcpy(buf, md_buf, md_len); 102*5b0945b5SGregory Neil Shapiro return (int)md_len; 103*5b0945b5SGregory Neil Shapiro } 104*5b0945b5SGregory Neil Shapiro 105*5b0945b5SGregory Neil Shapiro #if DANE 106*5b0945b5SGregory Neil Shapiro 107*5b0945b5SGregory Neil Shapiro /* 108*5b0945b5SGregory Neil Shapiro ** PUBKEY_FP -- get public key fingerprint 109*5b0945b5SGregory Neil Shapiro ** 110*5b0945b5SGregory Neil Shapiro ** Parameters: 111*5b0945b5SGregory Neil Shapiro ** cert -- TLS cert 112*5b0945b5SGregory Neil Shapiro ** mdalg -- name of digest algorithm 113*5b0945b5SGregory Neil Shapiro ** fp -- (pointer to) fingerprint buffer 114*5b0945b5SGregory Neil Shapiro ** 115*5b0945b5SGregory Neil Shapiro ** Returns: 116*5b0945b5SGregory Neil Shapiro ** <=0: cert fp calculation failed 117*5b0945b5SGregory Neil Shapiro ** >0: len of fp 118*5b0945b5SGregory Neil Shapiro */ 119*5b0945b5SGregory Neil Shapiro 120*5b0945b5SGregory Neil Shapiro int 121*5b0945b5SGregory Neil Shapiro pubkey_fp(cert, mdalg, fp) 122*5b0945b5SGregory Neil Shapiro X509 *cert; 123*5b0945b5SGregory Neil Shapiro const char *mdalg; 124*5b0945b5SGregory Neil Shapiro char **fp; 125*5b0945b5SGregory Neil Shapiro { 126*5b0945b5SGregory Neil Shapiro int len, r; 127*5b0945b5SGregory Neil Shapiro unsigned char *buf, *end; 128*5b0945b5SGregory Neil Shapiro const EVP_MD *md; 129*5b0945b5SGregory Neil Shapiro 130*5b0945b5SGregory Neil Shapiro SM_ASSERT(cert != NULL); 131*5b0945b5SGregory Neil Shapiro SM_ASSERT(fp != NULL); 132*5b0945b5SGregory Neil Shapiro SM_ASSERT(mdalg != NULL); 133*5b0945b5SGregory Neil Shapiro 134*5b0945b5SGregory Neil Shapiro len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL); 135*5b0945b5SGregory Neil Shapiro 136*5b0945b5SGregory Neil Shapiro /* what's an acceptable upper limit? */ 137*5b0945b5SGregory Neil Shapiro if (len <= 0 || len >= 8192) 138*5b0945b5SGregory Neil Shapiro return -EINVAL; 139*5b0945b5SGregory Neil Shapiro if (len < EVP_MAX_MD_SIZE) 140*5b0945b5SGregory Neil Shapiro len = EVP_MAX_MD_SIZE; 141*5b0945b5SGregory Neil Shapiro end = buf = sm_malloc(len); 142*5b0945b5SGregory Neil Shapiro if (NULL == buf) 143*5b0945b5SGregory Neil Shapiro return -ENOMEM; 144*5b0945b5SGregory Neil Shapiro 145*5b0945b5SGregory Neil Shapiro if ('\0' == mdalg[0]) 146*5b0945b5SGregory Neil Shapiro { 147*5b0945b5SGregory Neil Shapiro r = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end); 148*5b0945b5SGregory Neil Shapiro if (r <= 0 || r != len) 149*5b0945b5SGregory Neil Shapiro return -EINVAL; 150*5b0945b5SGregory Neil Shapiro *fp = (char *)buf; 151*5b0945b5SGregory Neil Shapiro return len; 152*5b0945b5SGregory Neil Shapiro } 153*5b0945b5SGregory Neil Shapiro 154*5b0945b5SGregory Neil Shapiro md = EVP_get_digestbyname(mdalg); 155*5b0945b5SGregory Neil Shapiro if (NULL == md) 156*5b0945b5SGregory Neil Shapiro return DANE_VRFY_FAIL; 157*5b0945b5SGregory Neil Shapiro len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &end); 158*5b0945b5SGregory Neil Shapiro r = tls_data_md(buf, len, md); 159*5b0945b5SGregory Neil Shapiro if (r < 0) 160*5b0945b5SGregory Neil Shapiro sm_free(buf); 161*5b0945b5SGregory Neil Shapiro else 162*5b0945b5SGregory Neil Shapiro *fp = (char *)buf; 163*5b0945b5SGregory Neil Shapiro return r; 164*5b0945b5SGregory Neil Shapiro } 165*5b0945b5SGregory Neil Shapiro 166*5b0945b5SGregory Neil Shapiro /* 167*5b0945b5SGregory Neil Shapiro ** DANE_TLSA_CHK -- check whether a TLSA RR is ok to use 168*5b0945b5SGregory Neil Shapiro ** 169*5b0945b5SGregory Neil Shapiro ** Parameters: 170*5b0945b5SGregory Neil Shapiro ** rr -- RR 171*5b0945b5SGregory Neil Shapiro ** len -- length of RR 172*5b0945b5SGregory Neil Shapiro ** host -- name of host for RR (only for logging) 173*5b0945b5SGregory Neil Shapiro ** log -- whether to log problems 174*5b0945b5SGregory Neil Shapiro ** 175*5b0945b5SGregory Neil Shapiro ** Returns: 176*5b0945b5SGregory Neil Shapiro ** TLSA_*, see tls.h 177*5b0945b5SGregory Neil Shapiro */ 178*5b0945b5SGregory Neil Shapiro 179*5b0945b5SGregory Neil Shapiro int 180*5b0945b5SGregory Neil Shapiro dane_tlsa_chk(rr, len, host, log) 181*5b0945b5SGregory Neil Shapiro const char *rr; 182*5b0945b5SGregory Neil Shapiro int len; 183*5b0945b5SGregory Neil Shapiro const char *host; 184*5b0945b5SGregory Neil Shapiro bool log; 185*5b0945b5SGregory Neil Shapiro { 186*5b0945b5SGregory Neil Shapiro int alg; 187*5b0945b5SGregory Neil Shapiro 188*5b0945b5SGregory Neil Shapiro if (len < 4) 189*5b0945b5SGregory Neil Shapiro { 190*5b0945b5SGregory Neil Shapiro if (log && LogLevel > 8) 191*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, 192*5b0945b5SGregory Neil Shapiro "TLSA=%s, len=%d, status=bogus", 193*5b0945b5SGregory Neil Shapiro host, len); 194*5b0945b5SGregory Neil Shapiro return TLSA_BOGUS; 195*5b0945b5SGregory Neil Shapiro } 196*5b0945b5SGregory Neil Shapiro SM_ASSERT(rr != NULL); 197*5b0945b5SGregory Neil Shapiro 198*5b0945b5SGregory Neil Shapiro alg = (int)rr[2]; 199*5b0945b5SGregory Neil Shapiro if ((int)rr[0] == 3 && (int)rr[1] == 1 && (alg >= 0 || alg <= 2)) 200*5b0945b5SGregory Neil Shapiro return alg; 201*5b0945b5SGregory Neil Shapiro if (log && LogLevel > 9) 202*5b0945b5SGregory Neil Shapiro sm_syslog(LOG_NOTICE, NOQID, 203*5b0945b5SGregory Neil Shapiro "TLSA=%s, type=%d-%d-%d:%02x, status=unsupported", 204*5b0945b5SGregory Neil Shapiro host, (int)rr[0], (int)rr[1], (int)rr[2], 205*5b0945b5SGregory Neil Shapiro (int)rr[3]); 206*5b0945b5SGregory Neil Shapiro return TLSA_UNSUPP; 207*5b0945b5SGregory Neil Shapiro } 208*5b0945b5SGregory Neil Shapiro 209*5b0945b5SGregory Neil Shapiro /* 210*5b0945b5SGregory Neil Shapiro ** DANE_TLSA_CLR -- clear data in a dane_tlsa structure (for use) 211*5b0945b5SGregory Neil Shapiro ** 212*5b0945b5SGregory Neil Shapiro ** Parameters: 213*5b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to clear 214*5b0945b5SGregory Neil Shapiro ** 215*5b0945b5SGregory Neil Shapiro ** Returns: 216*5b0945b5SGregory Neil Shapiro ** 1 if NULL 217*5b0945b5SGregory Neil Shapiro ** 0 if ok 218*5b0945b5SGregory Neil Shapiro */ 219*5b0945b5SGregory Neil Shapiro 220*5b0945b5SGregory Neil Shapiro int 221*5b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa) 222*5b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa; 223*5b0945b5SGregory Neil Shapiro { 224*5b0945b5SGregory Neil Shapiro int i; 225*5b0945b5SGregory Neil Shapiro 226*5b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL) 227*5b0945b5SGregory Neil Shapiro return 1; 228*5b0945b5SGregory Neil Shapiro for (i = 0; i < dane_tlsa->dane_tlsa_n; i++) 229*5b0945b5SGregory Neil Shapiro { 230*5b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_rr[i]); 231*5b0945b5SGregory Neil Shapiro dane_tlsa->dane_tlsa_len[i] = 0; 232*5b0945b5SGregory Neil Shapiro } 233*5b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa->dane_tlsa_sni); 234*5b0945b5SGregory Neil Shapiro memset(dane_tlsa, '\0', sizeof(*dane_tlsa)); 235*5b0945b5SGregory Neil Shapiro return 0; 236*5b0945b5SGregory Neil Shapiro 237*5b0945b5SGregory Neil Shapiro } 238*5b0945b5SGregory Neil Shapiro 239*5b0945b5SGregory Neil Shapiro /* 240*5b0945b5SGregory Neil Shapiro ** DANE_TLSA_FREE -- free a dane_tlsa structure 241*5b0945b5SGregory Neil Shapiro ** 242*5b0945b5SGregory Neil Shapiro ** Parameters: 243*5b0945b5SGregory Neil Shapiro ** dane_tlsa -- dane_tlsa to free 244*5b0945b5SGregory Neil Shapiro ** 245*5b0945b5SGregory Neil Shapiro ** Returns: 246*5b0945b5SGregory Neil Shapiro ** 0 if ok 247*5b0945b5SGregory Neil Shapiro ** 1 if NULL 248*5b0945b5SGregory Neil Shapiro */ 249*5b0945b5SGregory Neil Shapiro 250*5b0945b5SGregory Neil Shapiro int 251*5b0945b5SGregory Neil Shapiro dane_tlsa_free(dane_tlsa) 252*5b0945b5SGregory Neil Shapiro dane_tlsa_P dane_tlsa; 253*5b0945b5SGregory Neil Shapiro { 254*5b0945b5SGregory Neil Shapiro if (dane_tlsa == NULL) 255*5b0945b5SGregory Neil Shapiro return 1; 256*5b0945b5SGregory Neil Shapiro dane_tlsa_clr(dane_tlsa); 257*5b0945b5SGregory Neil Shapiro SM_FREE(dane_tlsa); 258*5b0945b5SGregory Neil Shapiro return 0; 259*5b0945b5SGregory Neil Shapiro 260*5b0945b5SGregory Neil Shapiro } 261*5b0945b5SGregory Neil Shapiro #endif /* DANE */ 262*5b0945b5SGregory Neil Shapiro 263*5b0945b5SGregory Neil Shapiro #endif /* STARTTLS */ 264