Postfix3.3.1
tls_fprint.c
[詳解]
1 /*++
2 /* NAME
3 /* tls_fprint 3
4 /* SUMMARY
5 /* Digests fingerprints and all that.
6 /* SYNOPSIS
7 /* #include <tls.h>
8 /*
9 /* char *tls_serverid_digest(props, protomask, ciphers)
10 /* const TLS_CLIENT_START_PROPS *props;
11 /* long protomask;
12 /* const char *ciphers;
13 /*
14 /* char *tls_digest_encode(md_buf, md_len)
15 /* const unsigned char *md_buf;
16 /* const char *md_len;
17 /*
18 /* char *tls_data_fprint(buf, len, mdalg)
19 /* const char *buf;
20 /* int len;
21 /* const char *mdalg;
22 /*
23 /* char *tls_cert_fprint(peercert, mdalg)
24 /* X509 *peercert;
25 /* const char *mdalg;
26 /*
27 /* char *tls_pkey_fprint(peercert, mdalg)
28 /* X509 *peercert;
29 /* const char *mdalg;
30 /* DESCRIPTION
31 /* tls_digest_encode() converts a binary message digest to a hex ASCII
32 /* format with ':' separators between each pair of hex digits.
33 /* The return value is dynamically allocated with mymalloc(),
34 /* and the caller must eventually free it with myfree().
35 /*
36 /* tls_data_fprint() digests unstructured data, and encodes the digested
37 /* result via tls_digest_encode(). The return value is dynamically
38 /* allocated with mymalloc(), and the caller must eventually free it
39 /* with myfree().
40 /*
41 /* tls_cert_fprint() returns a fingerprint of the the given
42 /* certificate using the requested message digest, formatted
43 /* with tls_digest_encode(). Panics if the
44 /* (previously verified) digest algorithm is not found. The return
45 /* value is dynamically allocated with mymalloc(), and the caller
46 /* must eventually free it with myfree().
47 /*
48 /* tls_pkey_fprint() returns a public-key fingerprint; in all
49 /* other respects the function behaves as tls_cert_fprint().
50 /* The var_tls_bc_pkey_fprint variable enables an incorrect
51 /* algorithm that was used in Postfix versions 2.9.[0-5].
52 /* The return value is dynamically allocated with mymalloc(),
53 /* and the caller must eventually free it with myfree().
54 /*
55 /* tls_serverid_digest() suffixes props->serverid computed by the SMTP
56 /* client with "&" plus a digest of additional parameters
57 /* needed to ensure that re-used sessions are more likely to
58 /* be reused and that they will satisfy all protocol and
59 /* security requirements.
60 /* The return value is dynamically allocated with mymalloc(),
61 /* and the caller must eventually free it with myfree().
62 /*
63 /* Arguments:
64 /* .IP peercert
65 /* Server or client X.509 certificate.
66 /* .IP md_buf
67 /* The raw binary digest.
68 /* .IP md_len
69 /* The digest length in bytes.
70 /* .IP mdalg
71 /* Name of a message digest algorithm suitable for computing secure
72 /* (1st pre-image resistant) message digests of certificates. For now,
73 /* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
74 /* .IP buf
75 /* Input data for the message digest algorithm mdalg.
76 /* .IP len
77 /* The length of the input data.
78 /* .IP props
79 /* The client start properties for the session, which contains the
80 /* initial serverid from the SMTP client and the DANE verification
81 /* parameters.
82 /* .IP protomask
83 /* The mask of protocol exclusions.
84 /* .IP ciphers
85 /* The SSL client cipherlist.
86 /* LICENSE
87 /* .ad
88 /* .fi
89 /* This software is free. You can do with it whatever you want.
90 /* The original author kindly requests that you acknowledge
91 /* the use of his software.
92 /* AUTHOR(S)
93 /* Wietse Venema
94 /* IBM T.J. Watson Research
95 /* P.O. Box 704
96 /* Yorktown Heights, NY 10598, USA
97 /*
98 /* Viktor Dukhovni
99 /*--*/
100 
101 /* System library. */
102 
103 #include <sys_defs.h>
104 #include <ctype.h>
105 
106 #ifdef USE_TLS
107 #include <string.h>
108 
109 /* Utility library. */
110 
111 #include <msg.h>
112 #include <mymalloc.h>
113 #include <stringops.h>
114 
115 /* Global library. */
116 
117 #include <mail_params.h>
118 
119 /* TLS library. */
120 
121 #define TLS_INTERNAL
122 #include <tls.h>
123 
124 /* Application-specific. */
125 
126 static const char hexcodes[] = "0123456789ABCDEF";
127 
128 #define checkok(ret) (ok &= ((ret) ? 1 : 0))
129 #define digest_data(p, l) checkok(EVP_DigestUpdate(mdctx, (char *)(p), (l)))
130 #define digest_object(p) digest_data((p), sizeof(*(p)))
131 #define digest_string(s) digest_data((s), strlen(s)+1)
132 
133 #define digest_dane(dane, memb) do { \
134  if ((dane)->memb != 0) \
135  checkok(digest_tlsa_usage(mdctx, (dane)->memb, #memb)); \
136  } while (0)
137 
138 #define digest_tlsa_argv(tlsa, memb) do { \
139  if ((tlsa)->memb) { \
140  digest_string(#memb); \
141  for (dgst = (tlsa)->memb->argv; *dgst; ++dgst) \
142  digest_string(*dgst); \
143  } \
144  } while (0)
145 
146 /* digest_tlsa_usage - digest TA or EE match list sorted by alg and value */
147 
148 static int digest_tlsa_usage(EVP_MD_CTX * mdctx, TLS_TLSA *tlsa,
149  const char *usage)
150 {
151  char **dgst;
152  int ok = 1;
153 
154  for (digest_string(usage); tlsa; tlsa = tlsa->next) {
155  digest_string(tlsa->mdalg);
156  digest_tlsa_argv(tlsa, pkeys);
157  digest_tlsa_argv(tlsa, certs);
158  }
159  return (ok);
160 }
161 
162 /* tls_serverid_digest - suffix props->serverid with parameter digest */
163 
164 char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *props, long protomask,
165  const char *ciphers)
166 {
167  EVP_MD_CTX *mdctx;
168  const EVP_MD *md;
169  const char *mdalg;
170  unsigned char md_buf[EVP_MAX_MD_SIZE];
171  unsigned int md_len;
172  int ok = 1;
173  int i;
174  long sslversion;
175  VSTRING *result;
176 
177  /*
178  * Try to use sha256: our serverid choice should be strong enough to
179  * resist 2nd-preimage attacks with a difficulty comparable to that of
180  * DANE TLSA digests. Failing that, we compute serverid digests with the
181  * default digest, but DANE requires sha256 and sha512, so if we must
182  * fall back to our default digest, DANE support won't be available. We
183  * panic if the fallback algorithm is not available, as it was verified
184  * available in tls_client_init() and must not simply vanish.
185  */
186  if ((md = EVP_get_digestbyname(mdalg = "sha256")) == 0
187  && (md = EVP_get_digestbyname(mdalg = props->mdalg)) == 0)
188  msg_panic("digest algorithm \"%s\" not found", mdalg);
189 
190  /* Salt the session lookup key with the OpenSSL runtime version. */
191  sslversion = OpenSSL_version_num();
192 
193  mdctx = EVP_MD_CTX_create();
194  checkok(EVP_DigestInit_ex(mdctx, md, NULL));
195  digest_string(props->helo ? props->helo : "");
196  digest_object(&sslversion);
197  digest_object(&protomask);
198  digest_string(ciphers);
199 
200  /*
201  * All we get from the session cache is a single bit telling us whether
202  * the certificate is trusted or not, but we need to know whether the
203  * trust is CA-based (in that case we must do name checks) or whether it
204  * is a direct end-point match. We mustn't confuse the two, so it is
205  * best to process only TA trust in the verify callback and check the EE
206  * trust after. This works since re-used sessions always have access to
207  * the leaf certificate, while only the original session has the leaf and
208  * the full trust chain.
209  *
210  * Only the trust anchor matchlist is hashed into the session key. The end
211  * entity certs are not used to determine whether a certificate is
212  * trusted or not, rather these are rechecked against the leaf cert
213  * outside the verification callback, each time a session is created or
214  * reused.
215  *
216  * Therefore, the security context of the session does not depend on the EE
217  * matching data, which is checked separately each time. So we exclude
218  * the EE part of the DANE structure from the serverid digest.
219  *
220  * If the security level is "dane", we send SNI information to the peer.
221  * This may cause it to respond with a non-default certificate. Since
222  * certificates for sessions with no or different SNI data may not match,
223  * we must include the SNI name in the session id.
224  */
225  if (props->dane) {
226  digest_dane(props->dane, ta);
227 #if 0
228  digest_dane(props->dane, ee); /* See above */
229 #endif
230  digest_string(TLS_DANE_BASED(props->tls_level) ? props->host : "");
231  }
232  checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
233  EVP_MD_CTX_destroy(mdctx);
234  if (!ok)
235  msg_fatal("error computing %s message digest", mdalg);
236 
237  /* Check for OpenSSL contract violation */
238  if (md_len > EVP_MAX_MD_SIZE)
239  msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);
240 
241  /*
242  * Append the digest to the serverid. We don't compare this digest to
243  * any user-specified fingerprints. Therefore, we don't need to use a
244  * colon-separated format, which saves space in the TLS session cache and
245  * makes logging of session cache lookup keys more readable.
246  *
247  * This does however duplicate a few lines of code from the digest encoder
248  * for colon-separated cert and pkey fingerprints. If that is a
249  * compelling reason to consolidate, we could use that and append the
250  * result.
251  */
252  result = vstring_alloc(strlen(props->serverid) + 1 + 2 * md_len);
253  vstring_strcpy(result, props->serverid);
254  VSTRING_ADDCH(result, '&');
255  for (i = 0; i < md_len; i++) {
256  VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0xf0) >> 4U]);
257  VSTRING_ADDCH(result, hexcodes[(md_buf[i] & 0x0f)]);
258  }
259  VSTRING_TERMINATE(result);
260  return (vstring_export(result));
261 }
262 
263 /* tls_digest_encode - encode message digest binary blob as xx:xx:... */
264 
265 char *tls_digest_encode(const unsigned char *md_buf, int md_len)
266 {
267  int i;
268  char *result = mymalloc(md_len * 3);
269 
270  /* Check for contract violation */
271  if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
272  msg_panic("unexpectedly large message digest size: %u", md_len);
273 
274  /* No risk of overrunes, len is bounded by OpenSSL digest length */
275  for (i = 0; i < md_len; i++) {
276  result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
277  result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
278  result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
279  }
280  return (result);
281 }
282 
283 /* tls_data_fprint - compute and encode digest of binary object */
284 
285 char *tls_data_fprint(const char *buf, int len, const char *mdalg)
286 {
287  EVP_MD_CTX *mdctx;
288  const EVP_MD *md;
289  unsigned char md_buf[EVP_MAX_MD_SIZE];
290  unsigned int md_len;
291  int ok = 1;
292 
293  /* Previously available in "init" routine. */
294  if ((md = EVP_get_digestbyname(mdalg)) == 0)
295  msg_panic("digest algorithm \"%s\" not found", mdalg);
296 
297  mdctx = EVP_MD_CTX_create();
298  checkok(EVP_DigestInit_ex(mdctx, md, NULL));
299  digest_data(buf, len);
300  checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
301  EVP_MD_CTX_destroy(mdctx);
302  if (!ok)
303  msg_fatal("error computing %s message digest", mdalg);
304 
305  return (tls_digest_encode(md_buf, md_len));
306 }
307 
308 /* tls_cert_fprint - extract certificate fingerprint */
309 
310 char *tls_cert_fprint(X509 *peercert, const char *mdalg)
311 {
312  int len;
313  char *buf;
314  char *buf2;
315  char *result;
316 
317  len = i2d_X509(peercert, NULL);
318  buf2 = buf = mymalloc(len);
319  i2d_X509(peercert, (unsigned char **) &buf2);
320  if (buf2 - buf != len)
321  msg_panic("i2d_X509 invalid result length");
322 
323  result = tls_data_fprint(buf, len, mdalg);
324  myfree(buf);
325 
326  return (result);
327 }
328 
329 /* tls_pkey_fprint - extract public key fingerprint from certificate */
330 
331 char *tls_pkey_fprint(X509 *peercert, const char *mdalg)
332 {
334  const char *myname = "tls_pkey_fprint";
335  ASN1_BIT_STRING *key;
336  char *result;
337 
338  key = X509_get0_pubkey_bitstr(peercert);
339  if (key == 0)
340  msg_fatal("%s: error extracting legacy public-key fingerprint: %m",
341  myname);
342 
343  result = tls_data_fprint((char *) key->data, key->length, mdalg);
344  return (result);
345  } else {
346  int len;
347  char *buf;
348  char *buf2;
349  char *result;
350 
351  len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), NULL);
352  buf2 = buf = mymalloc(len);
353  i2d_X509_PUBKEY(X509_get_X509_PUBKEY(peercert), (unsigned char **) &buf2);
354  if (buf2 - buf != len)
355  msg_panic("i2d_X509_PUBKEY invalid result length");
356 
357  result = tls_data_fprint(buf, len, mdalg);
358  myfree(buf);
359  return (result);
360  }
361 }
362 
363 #endif
void myfree(void *ptr)
Definition: mymalloc.c:207
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define TLS_DANE_BASED(l)
Definition: tls.h:58
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
#define VSTRING_TERMINATE(vp)
Definition: vstring.h:74
#define VSTRING_ADDCH(vp, ch)
Definition: vstring.h:81
bool var_tls_bc_pkey_fprint
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
char * vstring_export(VSTRING *vp)
Definition: vstring.c:569
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150