FreeTDS API

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 #endif
39
51 #ifndef HAVE_GNUTLS
52 #error HAVE_GNUTLS not defines, this file should not be included
53 #endif
54
55 /* emulate GMP if not present */
56 #ifndef HAVE_GMP
57 #define HAVE_GMP 1
58
59 typedef struct {
60 gcry_mpi_t num;
61 } mpz_t[1];
62
63 #define mpz_powm(w,n,e,m) \
64 gcry_mpi_powm((w)->num, (n)->num, (e)->num, (m)->num);
65 #define mpz_init(n) do { (n)->num = NULL; } while(0)
66 #define mpz_clear(n) gcry_mpi_release((n)->num)
67
68 #endif
69
70
71 /* emulate Nettle is not present */
72 #ifndef HAVE_NETTLE
73 #define HAVE_NETTLE 1
74
75 typedef void nettle_random_func(void *ctx, size_t len, uint8_t *out);
76
77 static inline void
78 nettle_mpz_set_str_256_u(mpz_t x, unsigned length, const uint8_t *s)
79 {
80 gcry_mpi_scan(&x->num, GCRYMPI_FMT_USG, s, length, NULL);
81 }
82
83 static inline void
84 nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x)
85 {
86 gcry_mpi_print(GCRYMPI_FMT_USG, s, length, NULL, x->num);
87 }
88
89 struct asn1_der_iterator {
90 const unsigned char *data, *data_end;
91 unsigned long length;
92 unsigned long type;
93 };
94
95 enum asn1_iterator_result {
96 ASN1_ITERATOR_ERROR,
97 ASN1_ITERATOR_PRIMITIVE,
98 ASN1_ITERATOR_CONSTRUCTED,
99 ASN1_ITERATOR_END,
100 };
101
102 enum {
103 ASN1_SEQUENCE = ASN1_TAG_SEQUENCE,
104 };
105
106 static enum asn1_iterator_result
107 asn1_der_iterator_next(struct asn1_der_iterator *der)
108 {
109 unsigned char cls;
110 unsigned long tag;
111 int len;
112 long l;
113
114 if (asn1_get_tag_der(der->data, der->data_end - der->data, &cls, &len, &tag) != ASN1_SUCCESS)
115 return ASN1_ITERATOR_ERROR;
116 der->type = tag;
117 der->data += len;
118 l = asn1_get_length_der(der->data, der->data_end - der->data, &len);
119 if (l < 0)
120 return ASN1_ITERATOR_ERROR;
121 der->data += len;
122 der->length = l;
123 if (cls == ASN1_CLASS_STRUCTURED)
124 return ASN1_ITERATOR_CONSTRUCTED;
125 return ASN1_ITERATOR_PRIMITIVE;
126 }
127
128 static enum asn1_iterator_result
129 asn1_der_iterator_first(struct asn1_der_iterator *der, int size, const void *der_buf)
130 {
131 der->data = (const unsigned char *) der_buf;
132 der->data_end = der->data + size;
133
134 return asn1_der_iterator_next(der);
135 }
136
137 struct rsa_public_key {
138 unsigned size;
139 mpz_t n, e;
140 };
141
142 static void
143 rsa_public_key_init(struct rsa_public_key *key)
144 {
145 key->size = 0;
146 mpz_init(key->n);
147 mpz_init(key->e);
148 }
149
150 static void
151 rsa_public_key_clear(struct rsa_public_key *key)
152 {
153 mpz_clear(key->n);
154 mpz_clear(key->e);
155 }
156
157 static int
158 rsa_public_key_from_der_iterator(struct rsa_public_key *key, unsigned key_bits, struct asn1_der_iterator *der)
159 {
160 enum asn1_iterator_result ret;
161
162 ret = asn1_der_iterator_next(der);
163 if (ret != ASN1_ITERATOR_PRIMITIVE || der->type != ASN1_TAG_INTEGER)
164 return 0;
165 gcry_mpi_scan(&key->n->num, GCRYMPI_FMT_USG, der->data, der->length, NULL);
166 key->size = (gcry_mpi_get_nbits(key->n->num)+7)/8;
167 der->data += der->length;
168
169 ret = asn1_der_iterator_next(der);
170 if (ret != ASN1_ITERATOR_PRIMITIVE || der->type != ASN1_TAG_INTEGER)
171 return 0;
172 gcry_mpi_scan(&key->e->num, GCRYMPI_FMT_USG, der->data, der->length, NULL);
173
174 return 1;
175 }
176
177 static void
178 sha1(uint8_t *hash, const void *data, size_t len)
179 {
180 gcry_md_hash_buffer(GCRY_MD_SHA1, hash, data, len);
181 }
182 #else
183 static void
184 sha1(uint8_t *hash, const void *data, size_t len)
185 {
186 struct sha1_ctx ctx;
187 sha1_init(&ctx);
188 sha1_update(&ctx, len, (const uint8_t *) data);
189 sha1_digest(&ctx, 20, hash);
190 }
191 #endif
192
193
194 static void
195 rnd_func(void *ctx, size_t len, uint8_t * out)
196 {
197 tds_random_buffer(out, len);
198 }
199
200 #define dumpl(b,l) tdsdump_dump_buf(TDS_DBG_INFO1, #b, b, l)
201 #ifndef dumpl
202 #define dumpl(b,l) do {} while(0)
203 #endif
204 #define dump(b) dumpl(b, sizeof(b))
205
206 /* OAEP configuration parameters */
207 #define hash_func sha1
208 enum { hash_len = 20 }; /* sha1 length */
209 enum { key_size_max = 1024 }; /* max key in bytes */
210 static const char label[] = "";
211
212 static void
213 memxor(uint8_t *dest, const uint8_t *src, size_t len)
214 {
215 size_t n;
216 for (n = 0; n < len; ++n)
217 dest[n] = dest[n] ^ src[n];
218 }
219
220 static void
221 mgf_mask(uint8_t *dest, size_t dest_len, const uint8_t *mask, size_t mask_len)
222 {
223 unsigned n = 0;
224 uint8_t hash[hash_len];
225 uint8_t seed[mask_len + 4];
226
227 memcpy(seed, mask, mask_len);
228 /* we always have some data and check is done internally */
229 for (;;) {
230 TDS_PUT_UA4BE(seed+mask_len, n);
231
232 hash_func(hash, seed, sizeof(seed));
233 if (dest_len <= hash_len) {
234 memxor(dest, hash, dest_len);
235 break;
236 }
237
238 memxor(dest, hash, hash_len);
239 dest += hash_len;
240 dest_len -= hash_len;
241 ++n;
242 }
243 }
244
245 static int
246 oaep_encrypt(size_t key_size, void *random_ctx, nettle_random_func *random,
247 size_t length, const uint8_t *message, mpz_t m)
248 {
249 /* EM: 0x00 ROS (HASH 0x00.. 0x01 message) */
250 struct {
251 uint8_t all[1]; /* zero but used to access all data */
252 uint8_t ros[hash_len];
253 uint8_t db[key_size_max - hash_len - 1];
254 } em;
255 const unsigned db_len = key_size - hash_len - 1;
256
257 if (length + hash_len * 2 + 2 > key_size)
258 /* Message too long for this key. */
259 return 0;
260
261 /* create db */
262 memset(&em, 0, sizeof(em));
263 hash_func(em.db, label, strlen(label));
264 em.all[key_size - length - 1] = 0x1;
265 memcpy(em.all+(key_size - length), message, length);
266 dumpl(em.db, db_len);
267
268 /* create ros */
269 random(random_ctx, hash_len, em.ros);
270 dump(em.ros);
271
272 /* mask db */
273 mgf_mask(em.db, db_len, em.ros, hash_len);
274 dumpl(em.db, db_len);
275
276 /* mask ros */
277 mgf_mask(em.ros, hash_len, em.db, db_len);
278 dump(em.ros);
279
280 nettle_mpz_set_str_256_u(m, key_size, em.all);
281
282 return 1;
283 }
284
285 static int
286 rsa_encrypt_oaep(const struct rsa_public_key *key, void *random_ctx, nettle_random_func *random,
287 size_t length, const uint8_t *message, mpz_t gibberish)
288 {
289 if (!oaep_encrypt(key->size, random_ctx, random, length, message, gibberish))
290 return 0;
291
292 mpz_powm(gibberish, gibberish, key->e, key->n);
293 return 1;
294 }
295
296 static void*
297 tds5_rsa_encrypt(const void *key, size_t key_len, const void *nonce, size_t nonce_len, const char *pwd, size_t *em_size)
298 {
299 int ret;
300 mpz_t p;
301 gnutls_datum_t pubkey_datum = { (unsigned char *) key, key_len };
302 struct asn1_der_iterator der;
303 struct rsa_public_key pubkey;
304 uint8_t *message;
305 size_t message_len, pwd_len;
306 uint8_t *em = NULL;
307 unsigned char der_buf[2048];
308 size_t size = sizeof(der_buf);
309
310 mpz_init(p);
311 rsa_public_key_init(&pubkey);
312
313 pwd_len = strlen(pwd);
314 message_len = nonce_len + pwd_len;
315 message = tds_new(uint8_t, message_len);
316 if (!message)
317 return NULL;
318 memcpy(message, nonce, nonce_len);
319 memcpy(message + nonce_len, pwd, pwd_len);
320
321 /* use nettle directly */
322 /* parse PEM, get DER */
323 ret = gnutls_pem_base64_decode("RSA PUBLIC KEY", &pubkey_datum, der_buf, &size);
324 if (ret) {
325 tdsdump_log(TDS_DBG_ERROR, "Error %d decoding public key: %s\n", ret, gnutls_strerror(ret));
326 goto error;
327 }
328
329 /* get key with nettle using DER */
330 ret = asn1_der_iterator_first(&der, size, der_buf);
331 if (ret != ASN1_ITERATOR_CONSTRUCTED || der.type != ASN1_SEQUENCE) {
332 tdsdump_log(TDS_DBG_ERROR, "Invalid DER content\n");
333 goto error;
334 }
335
336 ret = rsa_public_key_from_der_iterator(&pubkey, key_size_max * 8, &der);
337 if (!ret) {
338 tdsdump_log(TDS_DBG_ERROR, "Invalid DER content\n");
339 goto error;
340 }
341
342 /* get password encrypted */
343 ret = rsa_encrypt_oaep(&pubkey, NULL, rnd_func, message_len, message, p);
344 if (!ret) {
345 tdsdump_log(TDS_DBG_ERROR, "Error encrypting message\n");
346 goto error;
347 }
348
349 em = tds_new(uint8_t, pubkey.size);
350 *em_size = pubkey.size;
351 if (!em)
352 goto error;
353
354 nettle_mpz_get_str_256(pubkey.size, em, p);
355
356 tdsdump_dump_buf(TDS_DBG_INFO1, "em", em, pubkey.size);
357
358 error:
359 free(message);
360 rsa_public_key_clear(&pubkey);
361 mpz_clear(p);
362 return em;
363 }
364
tds.h
tds_dstr_setlen
DSTR * tds_dstr_setlen(DSTR *s, size_t length)
limit length of string, MUST be <= current length
Definition: tdsstring.c:145
tds_packet
Definition: tds.h:1055
tds_column::column_size
TDS_INT column_size
maximun size of data.
Definition: tds.h:696
tds_convert_stream
TDSRET tds_convert_stream(TDSSOCKET *tds, TDSICONV *char_conv, TDS_ICONV_DIRECTION direction, TDSINSTREAM *istream, TDSOUTSTREAM *ostream)
Reads and writes from a stream converting characters.
Definition: stream.c:71
asn1_der_iterator
Definition: sec_negotiate_gnutls.h:89
tdsdump_log
void tdsdump_log(const char *file, unsigned int level_line, const char *fmt,...)
Write a message to the debug log.
Definition: log.c:354
tdsmoney
Definition: proto.h:38
tds_staticout_stream
output stream to write data to a static buffer.
Definition: stream.h:92
tds_flush_packet
TDSRET tds_flush_packet(TDSSOCKET *tds)
Flush packet to server.
Definition: write.c:285
tds_datain_stream
input stream to read data from tds protocol
Definition: stream.h:63
tds_socket::out_buf_max
unsigned int out_buf_max
Maximum size of packet pointed by out_buf.
Definition: tds.h:1167
tds_dstr_alloc
DSTR * tds_dstr_alloc(DSTR *s, size_t length)
allocate space for length char
Definition: tdsstring.c:165
tds_socket::in_cancel
volatile unsigned char in_cancel
indicate we are waiting a cancel reply; discard tokens till acknowledge; 1 mean we have to send cance...
Definition: tds.h:1206
mpz_t
Definition: sec_negotiate_gnutls.h:59
tdsiconvinfo
Definition: iconv.h:91
tds_get_uint
TDS_UINT tds_get_uint(TDSSOCKET *tds)
Get an int32 from the server.
Definition: read.c:131
tds_set_state
TDS_STATE tds_set_state(TDSSOCKET *tds, TDS_STATE state)
Set state of TDS connection, with logging and checking.
Definition: util.c:58
tds_socket::in_len
unsigned in_len
input buffer length
Definition: tds.h:1170
tds_get_char_data
TDSRET tds_get_char_data(TDSSOCKET *tds, char *row_buffer, size_t wire_size, TDSCOLUMN *curcol)
Fetch character data the wire.
Definition: read.c:213
tds_column::char_conv
TDSICONV * char_conv
refers to previously allocated iconv information
Definition: tds.h:714
tds_datain_stream_init
void tds_datain_stream_init(TDSDATAINSTREAM *stream, TDSSOCKET *tds, size_t wire_size)
Initialize a data input stream.
Definition: stream.c:204
tds_put_tinyint
#define tds_put_tinyint(tds, ti)
Output a tinyint value.
Definition: tds.h:1422
tds_dstr_buf
static char * tds_dstr_buf(DSTR *s)
Returns a buffer to edit the string.
Definition: string.h:71
tds_dstr
Structure to hold a string.
Definition: string.h:36
tds_column
Metadata about columns in regular and compute rows.
Definition: tds.h:690
tds_dstr_get
DSTR * tds_dstr_get(TDSSOCKET *tds, DSTR *s, size_t len)
Reads a string from wire and put in a DSTR.
Definition: read.c:311
tds_socket::out_pos
unsigned out_pos
current position in out_buf
Definition: tds.h:1169
tds_connection::env
TDSENV env
environment is shared between all sessions
Definition: tds.h:1080
TDS_DEAD
@ TDS_DEAD
no connection
Definition: tds.h:796
tds_env::block_size
int block_size
packet size (512-65535)
Definition: tds.h:966
read_and_convert
static size_t read_and_convert(TDSSOCKET *tds, TDSICONV *char_conv, size_t *wire_size, char *outbuf, size_t outbytesleft)
For UTF-8 and similar, tds_iconv() may encounter a partial sequence when the chunk boundary is not al...
Definition: read.c:287
tds_get_n
bool tds_get_n(TDSSOCKET *tds, void *dest, size_t need)
Get N bytes from the buffer and return them in the already allocated space given to us.
Definition: read.c:248
tds_dstr_cstr
static const char * tds_dstr_cstr(const DSTR *s)
Returns a C version (NUL terminated string) of dstr.
Definition: string.h:78
TDS72_SMP_HEADER
TDS 7.2 SMP packet header.
Definition: proto.h:360
tds_socket::in_flag
unsigned char in_flag
input buffer type
Definition: tds.h:1171
tds_numeric_to_string
TDS_INT tds_numeric_to_string(const TDS_NUMERIC *numeric, char *s)
Definition: numeric.c:95
tds_result_info
Hold information for any results.
Definition: tds.h:769
tds_staticout_stream_init
void tds_staticout_stream_init(TDSSTATICOUTSTREAM *stream, void *ptr, size_t len)
Initialize an output stream for write into a static allocated buffer.
Definition: stream.c:313
tds_unget_byte
void tds_unget_byte(TDSSOCKET *tds)
Unget will always work as long as you don't call it twice in a row.
Definition: read.c:89
tds_get_string
size_t tds_get_string(TDSSOCKET *tds, size_t string_len, char *dest, size_t dest_size)
Fetch a string from the wire.
Definition: read.c:184
tds_read_packet
int tds_read_packet(TDSSOCKET *tds)
Read in one 'packet' from the server.
Definition: packet.c:531
tds_get_uint8
TDS_UINT8 tds_get_uint8(TDSSOCKET *tds)
Get an uint64 from the server.
Definition: read.c:148
tds_socket::out_buf
unsigned char * out_buf
Output buffer.
Definition: tds.h:1161
tds_column::column_type
TDS_SERVER_TYPE column_type
This type can be different from wire type because conversion (e.g.
Definition: tds.h:698
tds_authentication
Definition: tds.h:1047
tds_socket::in_pos
unsigned in_pos
current position in in_buf
Definition: tds.h:1168
poll.h
Provide poll call where missing.
tds_peek
unsigned char tds_peek(TDSSOCKET *tds)
Reads a byte from the TDS stream without removing it.
Definition: read.c:100
tds_blob
Information about blobs (e.g.
Definition: tds.h:587
tds_get_usmallint
TDS_USMALLINT tds_get_usmallint(TDSSOCKET *tds)
Get an int16 from the server.
Definition: read.c:113
tds_output_stream::buffer
char * buffer
write buffer.
Definition: stream.h:50
tds_select
int tds_select(TDSSOCKET *tds, unsigned tds_sel, int timeout_seconds)
Select on a socket until it's available or the timeout expires.
Definition: net.c:612
tdsnumeric
Definition: proto.h:25
tds_socket::in_buf
unsigned char * in_buf
Input buffer.
Definition: tds.h:1154
tds_get_byte
unsigned char tds_get_byte(TDSSOCKET *tds)
Return a single byte from the input buffer.
Definition: read.c:72
tds_socket::out_flag
unsigned char out_flag
output buffer type
Definition: tds.h:1172
tdserror
int tdserror(const TDSCONTEXT *tds_ctx, TDSSOCKET *tds, int msgno, int errnum)
Call the client library's error handler (for library-generated errors only)
Definition: util.c:307
tds_login::password
DSTR password
password of account login
Definition: tds.h:530
tds_socket
Information for a server connection.
Definition: tds.h:1141
rsa_public_key
Definition: sec_negotiate_gnutls.h:137
tds_close_socket
void tds_close_socket(TDSSOCKET *tds)
Close current socket.
Definition: net.c:548
tds_socket::login
TDSLOGIN * login
config for login stuff.
Definition: tds.h:1214
tds_datain_stream::wire_size
size_t wire_size
bytes still to read
Definition: stream.h:65
tdsdump_dump_buf
void tdsdump_dump_buf(const char *file, unsigned int level_line, const char *msg, const void *buf, size_t length)
Dump the contents of data into the log file in a human readable format.
Definition: log.c:256
tds_connection
Definition: tds.h:1069
tds_numeric_bytes_per_prec
const int tds_numeric_bytes_per_prec[]
The following little table is indexed by precision and will tell us the number of bytes required to s...
Definition: numeric.c:41
tds_column::column_cur_size
TDS_INT column_cur_size
size written in variable (ie: char, text, binary).
Definition: tds.h:737