The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
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: 318d82650ef2ec04ad654069d8747d6fd94ed8b5 $
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 */
45char 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 */
115int 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 (size_t) (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 (size_t) (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 (size_t) (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 */
170done:
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 */
190int 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:209
#define UNUSED
Definition build.h:315
#define NUM_ELEMENTS(_t)
Definition build.h:337
#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