The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
utils.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16 
17 /**
18  * $Id: 2b3eebd4e0bbeb0f2a97b9b4e9976accc6d9dd64 $
19  *
20  * @file tls/utils.c
21  * @brief TLS utility functions
22  *
23  * @copyright 2018 The FreeRADIUS server project
24  */
25 
26 #include "utils.h"
27 #include <openssl/ssl.h>
28 
29 /** PKEY types (friendly names)
30  *
31  */
33  { L("DH"), EVP_PKEY_DH },
34  { L("DSA"), EVP_PKEY_DSA },
35  { L("EC"), EVP_PKEY_EC },
36  { L("RSA"), EVP_PKEY_RSA }
37 };
39 
40 /** Returns a friendly identifier for the public key type of a certificate
41  *
42  * @param[in] cert The X509 cert to return the type of.
43  * @return the type string.
44  */
45 char const *fr_tls_utils_x509_pkey_type(X509 *cert)
46 {
47  EVP_PKEY *pkey;
48  int pkey_type;
49  char const *type_str;
50 
51  if (!cert) return NULL;
52 
53  pkey = X509_get_pubkey(cert);
54  if (!pkey) return NULL;
55 
56  pkey_type = EVP_PKEY_type(EVP_PKEY_id(pkey));
57  type_str = fr_table_str_by_value(pkey_types, pkey_type, OBJ_nid2sn(pkey_type));
58  EVP_PKEY_free(pkey);
59 
60  return type_str;
61 }
62 
63 /** Returns the OpenSSL keyblock size
64  *
65  * @copyright (c) 2002-2016, Jouni Malinen (j@w1.fi) and contributors
66  * All Rights Reserved.
67  *
68  * These programs are licensed under the BSD license (the one with
69  * advertisement clause removed).
70  *
71  * this function shamelessly stolen from from
72  * hostap:src/crypto/tls_openssl.c:openssl_get_keyblock_size()
73  *
74  * @param[in] request The current request.
75  * @param[in] ssl The current SSL session.
76  * @return
77  * - -1 problem with the session.
78  * - >=0 length of the block.
79  */
81 {
82  const EVP_CIPHER *c;
83  const EVP_MD *h;
84  const SSL_CIPHER *ssl_cipher;
85  int cipher, digest;
86 
87  ssl_cipher = SSL_get_current_cipher(ssl);
88  if (!ssl_cipher)
89  return -1;
90  cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
91  digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
92  RDEBUG2("OpenSSL: cipher nid %d digest nid %d", cipher, digest);
93  if (cipher < 0 || digest < 0)
94  return -1;
95  c = EVP_get_cipherbynid(cipher);
96  h = EVP_get_digestbynid(digest);
97  if (!c || !h)
98  return -1;
99 
100  RDEBUG2("OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
101  EVP_CIPHER_key_length(c), EVP_MD_size(h),
102  EVP_CIPHER_iv_length(c));
103  return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
104  EVP_CIPHER_iv_length(c));
105 }
106 
107 /** Convert OpenSSL's ASN1_TIME to an epoch time
108  *
109  * @param[out] out Where to write the time_t.
110  * @param[in] asn1 The ASN1_TIME to convert.
111  * @return
112  * - 0 success.
113  * - -1 on failure.
114  */
115 int fr_tls_utils_asn1time_to_epoch(time_t *out, ASN1_TIME const *asn1)
116 {
117  struct tm t;
118  char const *p = (char const *)asn1->data, *end = p + strlen(p);
119 
120  memset(&t, 0, sizeof(t));
121 
122  if (asn1->type == V_ASN1_UTCTIME) {/* two digit year */
123  if ((end - p) < 2) {
124  fr_strerror_printf("ASN1 date string too short, expected 2 additional bytes, got %zu bytes",
125  end - p);
126  return -1;
127  }
128 
129  t.tm_year = (*(p++) - '0') * 10;
130  t.tm_year += (*(p++) - '0');
131  if (t.tm_year < 70) t.tm_year += 100;
132  } else if (asn1->type == V_ASN1_GENERALIZEDTIME) {/* four digit year */
133  if ((end - p) < 4) {
134  fr_strerror_printf("ASN1 string too short, expected 4 additional bytes, got %zu bytes",
135  end - p);
136  return -1;
137  }
138 
139  t.tm_year = (*(p++) - '0') * 1000;
140  t.tm_year += (*(p++) - '0') * 100;
141  t.tm_year += (*(p++) - '0') * 10;
142  t.tm_year += (*(p++) - '0');
143  t.tm_year -= 1900;
144  }
145 
146  if ((end - p) < 4) {
147  fr_strerror_printf("ASN1 string too short, expected 10 additional bytes, got %zu bytes",
148  end - p);
149  return -1;
150  }
151 
152  t.tm_mon = (*(p++) - '0') * 10;
153  t.tm_mon += (*(p++) - '0') - 1; // -1 since January is 0 not 1.
154  t.tm_mday = (*(p++) - '0') * 10;
155  t.tm_mday += (*(p++) - '0');
156 
157  if ((end - p) < 2) goto done;
158  t.tm_hour = (*(p++) - '0') * 10;
159  t.tm_hour += (*(p++) - '0');
160 
161  if ((end - p) < 2) goto done;
162  t.tm_min = (*(p++) - '0') * 10;
163  t.tm_min += (*(p++) - '0');
164 
165  if ((end - p) < 2) goto done;
166  t.tm_sec = (*(p++) - '0') * 10;
167  t.tm_sec += (*(p++) - '0');
168 
169  /* ASN1_TIME is UTC, so get the UTC time */
170 done:
171  *out = timegm(&t);
172 
173  return 0;
174 }
175 
176 /** Return the static private key password we have configured
177  *
178  * @note This is used as a callback to OpenSSL's PEM_read_PrivateKey function.
179 
180  * @param[out] buf Where to write the password to.
181  * @param[in] size The length of buf.
182  * @param[in] rwflag
183  * - 0 if password used for decryption.
184  * - 1 if password used for encryption.
185  * @param[in] u The static password.
186  * @return
187  * - 0 on error.
188  * - >0 on success (the length of the password).
189  */
190 int fr_utils_get_private_key_password(char *buf, int size, UNUSED int rwflag, void *u)
191 {
192  char *pass;
193  size_t len;
194 
195  if (!u) {
196  ERROR("Private key encrypted but no private_key_password configured");
197  return 0;
198  }
199 
200  pass = talloc_get_type_abort(u, char);
201  len = talloc_array_length(pass); /* Len includes \0 */
202  if (len > (size_t)size) {
203  ERROR("Password too long. Maximum length is %i bytes", size - 1);
204  return -1;
205  }
206  memcpy(buf, pass, len); /* Copy complete password including \0 byte */
207 
208  return len - 1;
209 }
#define L(_str)
Helper for initialising arrays of string literals.
Definition: build.h:207
#define UNUSED
Definition: build.h:313
#define NUM_ELEMENTS(_t)
Definition: build.h:335
#define ERROR(fmt,...)
Definition: dhcpclient.c:41
static bool done
Definition: radclient.c:80
#define RDEBUG2(fmt,...)
Definition: radclient.h:54
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition: table.h:772
An element in a lexicographically sorted array of name to num mappings.
Definition: table.h:49
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition: strerror.h:64
int fr_utils_get_private_key_password(char *buf, int size, UNUSED int rwflag, void *u)
Return the static private key password we have configured.
Definition: utils.c:190
char const * fr_tls_utils_x509_pkey_type(X509 *cert)
Returns a friendly identifier for the public key type of a certificate.
Definition: utils.c:45
int fr_tls_utils_asn1time_to_epoch(time_t *out, ASN1_TIME const *asn1)
Convert OpenSSL's ASN1_TIME to an epoch time.
Definition: utils.c:115
int fr_tls_utils_keyblock_size_get(request_t *request, SSL *ssl)
Returns the OpenSSL keyblock size.
Definition: utils.c:80
static size_t pkey_types_len
Definition: utils.c:38
static fr_table_num_sorted_t const pkey_types[]
PKEY types (friendly names)
Definition: utils.c:32
static size_t char ** out
Definition: value.h:997