FreeTDS API: src/tds/sec_negotiate_gnutls.h Source File

FreeTDS API

Loading...
Searching...
No Matches
sec_negotiate_gnutls.h
1/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 * Copyright (C) 2015 Frediano Ziglio
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19
20#include <gnutls/gnutls.h>
21#include <gnutls/crypto.h>
22#ifdef HAVE_GNUTLS_ABSTRACT_H
23# include <gnutls/abstract.h>
24#endif
25
26#if !defined(HAVE_NETTLE) || !defined(HAVE_GMP) || !defined(HAVE_GNUTLS_RND)
27# include <gcrypt.h>
28#endif
29
30#ifndef HAVE_NETTLE
31# include <libtasn1.h>
32#endif
33
34#ifdef HAVE_NETTLE
35# include <nettle/asn1.h>
36# include <nettle/rsa.h>
37# include <nettle/bignum.h>
38# include <nettle/version.h>
39#endif
40
46
51
52#ifndef HAVE_GNUTLS
53#error HAVE_GNUTLS not defined, this file should not be included
54#endif
55
56/* emulate GMP if not present */
57#ifndef HAVE_GMP
58#define HAVE_GMP 1
59
60 typedef struct {
61 gcry_mpi_t num;
62} mpz_t[1];
63
64#define mpz_powm(w,n,e,m) \
65 gcry_mpi_powm((w)->num, (n)->num, (e)->num, (m)->num);
66#define mpz_init(n) do { (n)->num = NULL; } while(0)
67#define mpz_clear(n) gcry_mpi_release((n)->num)
68
69#endif
70
71
72/* emulate Nettle if not present */
73#ifndef HAVE_NETTLE
74#define HAVE_NETTLE 1
75
76typedef void nettle_random_func(void *ctx, size_t len, uint8_t *out);
77
78static inline void
79nettle_mpz_set_str_256_u(mpz_t x, unsigned length, const uint8_t *s)
80{
81 gcry_mpi_scan(&x->num, GCRYMPI_FMT_USG, s, length, NULL);
82}
83
84static inline void
85nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x)
86{
87 gcry_mpi_print(GCRYMPI_FMT_USG, s, length, NULL, x->num);
88}
89
90 struct asn1_der_iterator {
91 const unsigned char *data, *data_end;
92 unsigned long length;
93 unsigned long type;
94};
95
96enum asn1_iterator_result {
97 ASN1_ITERATOR_ERROR,
98 ASN1_ITERATOR_PRIMITIVE,
99 ASN1_ITERATOR_CONSTRUCTED,
100 ASN1_ITERATOR_END,
101};
102
103enum {
104 ASN1_SEQUENCE = ASN1_TAG_SEQUENCE,
105};
106
107static enum asn1_iterator_result
108asn1_der_iterator_next(struct asn1_der_iterator *der)
109{
110 unsigned char cls;
111 unsigned long tag;
112 int len;
113 long l;
114
115 if (asn1_get_tag_der(der->data, der->data_end - der->data, &cls, &len, &tag) != ASN1_SUCCESS)
116 return ASN1_ITERATOR_ERROR;
117 der->type = tag;
118 der->data += len;
119 l = asn1_get_length_der(der->data, der->data_end - der->data, &len);
120 if (l < 0)
121 return ASN1_ITERATOR_ERROR;
122 der->data += len;
123 der->length = l;
124 if (cls == ASN1_CLASS_STRUCTURED)
125 return ASN1_ITERATOR_CONSTRUCTED;
126 return ASN1_ITERATOR_PRIMITIVE;
127}
128
129static enum asn1_iterator_result
130asn1_der_iterator_first(struct asn1_der_iterator *der, int size, const void *der_buf)
131{
132 der->data = (const unsigned char *) der_buf;
133 der->data_end = der->data + size;
134
135 return asn1_der_iterator_next(der);
136}
137
138 struct rsa_public_key {
139 unsigned size;
140 mpz_t n, e;
141};
142
143static void
144rsa_public_key_init(struct rsa_public_key *key)
145{
146 key->size = 0;
147 mpz_init(key->n);
148 mpz_init(key->e);
149}
150
151static void
152rsa_public_key_clear(struct rsa_public_key *key)
153{
154 mpz_clear(key->n);
155 mpz_clear(key->e);
156}
157
158static int
159rsa_public_key_from_der_iterator(struct rsa_public_key *key, unsigned key_bits, struct asn1_der_iterator *der)
160{
161 enum asn1_iterator_result ret;
162
163 ret = asn1_der_iterator_next(der);
164 if (ret != ASN1_ITERATOR_PRIMITIVE || der->type != ASN1_TAG_INTEGER)
165 return 0;
166 gcry_mpi_scan(&key->n->num, GCRYMPI_FMT_USG, der->data, der->length, NULL);
167 key->size = (gcry_mpi_get_nbits(key->n->num)+7)/8;
168 der->data += der->length;
169
170 ret = asn1_der_iterator_next(der);
171 if (ret != ASN1_ITERATOR_PRIMITIVE || der->type != ASN1_TAG_INTEGER)
172 return 0;
173 gcry_mpi_scan(&key->e->num, GCRYMPI_FMT_USG, der->data, der->length, NULL);
174
175 return 1;
176}
177
178static void
179sha1(uint8_t *hash, const void *data, size_t len)
180{
181 gcry_md_hash_buffer(GCRY_MD_SHA1, hash, data, len);
182}
183#else
184static void
185sha1(uint8_t *hash, const void *data, size_t len)
186{
187 struct sha1_ctx ctx;
188 sha1_init(&ctx);
189 sha1_update(&ctx, len, (const uint8_t *) data);
190#if defined(NETTLE_VERSION_MAJOR) && NETTLE_VERSION_MAJOR >= 4
191 sha1_digest(&ctx, hash);
192#else
193 sha1_digest(&ctx, 20, hash);
194#endif
195}
196#endif
197
198
199#define dumpl(b,l) tdsdump_dump_buf(TDS_DBG_INFO1, #b, b, l)
200#ifndef dumpl
201#define dumpl(b,l) do {} while(0)
202#endif
203#define dump(b) dumpl(b, sizeof(b))
204
205/* OAEP configuration parameters */
206#define hash_func sha1
207enum { hash_len = 20 }; /* sha1 length */
208enum { key_size_max = 1024 }; /* max key in bytes */
209static const char label[] = "";
210
211static void
212memxor(uint8_t *dest, const uint8_t *src, size_t len)
213{
214 size_t n;
215 for (n = 0; n < len; ++n)
216 dest[n] = dest[n] ^ src[n];
217}
218
219static void
220mgf_mask(uint8_t *dest, size_t dest_len, const uint8_t *mask, size_t mask_len)
221{
222 unsigned n = 0;
223 uint8_t hash[hash_len];
224 uint8_t seed[mask_len + 4];
225
226 memcpy(seed, mask, mask_len);
227 /* we always have some data and check is done internally */
228 for (;;) {
229 TDS_PUT_UA4BE(seed+mask_len, n);
230
231 hash_func(hash, seed, sizeof(seed));
232 if (dest_len <= hash_len) {
233 memxor(dest, hash, dest_len);
234 break;
235 }
236
237 memxor(dest, hash, hash_len);
238 dest += hash_len;
239 dest_len -= hash_len;
240 ++n;
241 }
242}
243
244static int
245oaep_encrypt(size_t key_size, size_t length, const uint8_t *message, mpz_t m)
246{
247 /* EM: 0x00 ROS (HASH 0x00.. 0x01 message) */
248 struct {
249 uint8_t all[1]; /* zero but used to access all data */
250 uint8_t ros[hash_len];
251 uint8_t db[key_size_max - hash_len - 1];
252 } em;
253 const unsigned db_len = key_size - hash_len - 1;
254
255 if (length + hash_len * 2 + 2 > key_size)
256 /* Message too long for this key. */
257 return 0;
258
259 /* create db */
260 memset(&em, 0, sizeof(em));
261 hash_func(em.db, label, strlen(label));
262 em.all[key_size - length - 1] = 0x1;
263 memcpy(em.all+(key_size - length), message, length);
264 dumpl(em.db, db_len);
265
266 /* create ros */
267 tds_random_buffer(em.ros, hash_len);
268 dump(em.ros);
269
270 /* mask db */
271 mgf_mask(em.db, db_len, em.ros, hash_len);
272 dumpl(em.db, db_len);
273
274 /* mask ros */
275 mgf_mask(em.ros, hash_len, em.db, db_len);
276 dump(em.ros);
277
278 nettle_mpz_set_str_256_u(m, key_size, em.all);
279
280 return 1;
281}
282
283static int
284rsa_encrypt_oaep(const struct rsa_public_key *key,
285 size_t length, const uint8_t *message, mpz_t gibberish)
286{
287 if (!oaep_encrypt(key->size, length, message, gibberish))
288 return 0;
289
290 mpz_powm(gibberish, gibberish, key->e, key->n);
291 return 1;
292}
293
294static void*
295tds5_rsa_encrypt(const void *key, size_t key_len, const void *nonce, size_t nonce_len, const char *pwd, size_t *em_size)
296{
297 int ret;
298 mpz_t p;
299 gnutls_datum_t pubkey_datum = { (unsigned char *) key, key_len };
300 struct asn1_der_iterator der;
301 struct rsa_public_key pubkey;
302 uint8_t *message;
303 size_t message_len, pwd_len;
304 uint8_t *em = NULL;
305 unsigned char der_buf[2048];
306 size_t size = sizeof(der_buf);
307
308 mpz_init(p);
309 rsa_public_key_init(&pubkey);
310
311 pwd_len = strlen(pwd);
312 message_len = nonce_len + pwd_len;
313 message = tds_new(uint8_t, message_len);
314 if (!message)
315 return NULL;
316 memcpy(message, nonce, nonce_len);
317 memcpy(message + nonce_len, pwd, pwd_len);
318
319 /* use nettle directly */
320 /* parse PEM, get DER */
321 ret = gnutls_pem_base64_decode("RSA PUBLIC KEY", &pubkey_datum, der_buf, &size);
322 if (ret) {
323 tdsdump_log(TDS_DBG_ERROR, "Error %d decoding public key: %s\n", ret, gnutls_strerror(ret));
324 goto error;
325 }
326
327 /* get key with nettle using DER */
328 ret = asn1_der_iterator_first(&der, size, der_buf);
329 if (ret != ASN1_ITERATOR_CONSTRUCTED || der.type != ASN1_SEQUENCE) {
330 tdsdump_log(TDS_DBG_ERROR, "Invalid DER content\n");
331 goto error;
332 }
333
334 ret = rsa_public_key_from_der_iterator(&pubkey, key_size_max * 8, &der);
335 if (!ret) {
336 tdsdump_log(TDS_DBG_ERROR, "Invalid DER content\n");
337 goto error;
338 }
339
340 /* get password encrypted */
341 ret = rsa_encrypt_oaep(&pubkey, message_len, message, p);
342 if (!ret) {
343 tdsdump_log(TDS_DBG_ERROR, "Error encrypting message\n");
344 goto error;
345 }
346
347 em = tds_new(uint8_t, pubkey.size);
348 *em_size = pubkey.size;
349 if (!em)
350 goto error;
351
352 nettle_mpz_get_str_256(pubkey.size, em, p);
353
354 tdsdump_dump_buf(TDS_DBG_INFO1, "em", em, pubkey.size);
355
356error:
357 free(message);
358 rsa_public_key_clear(&pubkey);
359 mpz_clear(p);
360 return em;
361}
362
364
mpz_t
Definition sec_negotiate_gnutls.h:60
asn1_der_iterator
Definition sec_negotiate_gnutls.h:90
rsa_public_key
Definition sec_negotiate_gnutls.h:138