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 <openssl/rand.h>
21 #include <openssl/bio.h>
22 #include <openssl/pem.h>
23 #include <openssl/err.h>
24
25 /**
26 * \ingroup libtds
27 * \defgroup auth Authentication
28 * Functions for handling authentication.
29 */
30
31 /**
32 * \addtogroup auth
33 * @{
34 */
35
36 #ifndef HAVE_OPENSSL
37 #error HAVE_OPENSSL not defines, this file should not be included
38 #endif
39
40 static inline const BIGNUM*
rsa_get_n(const RSA * rsa)41 rsa_get_n(const RSA *rsa)
42 {
43 #if OPENSSL_VERSION_NUMBER >= 0x1010000FL
44 const BIGNUM *n, *e, *d;
45 RSA_get0_key(rsa, &n, &e, &d);
46 return n;
47 #else
48 return rsa->n;
49 #endif
50 }
51
52 static void*
tds5_rsa_encrypt(const void * key,size_t key_len,const void * nonce,size_t nonce_len,const char * pwd,size_t * em_size)53 tds5_rsa_encrypt(const void *key, size_t key_len, const void *nonce, size_t nonce_len, const char *pwd, size_t *em_size)
54 {
55 RSA *rsa = NULL;
56 BIO *keybio;
57
58 TDS_UCHAR *message = NULL;
59 size_t message_len, pwd_len;
60 TDS_UCHAR *em = NULL;
61
62 int result;
63
64 keybio = BIO_new_mem_buf((void*) key, key_len);
65 if (keybio == NULL)
66 goto error;
67
68 rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
69 if (!rsa)
70 goto error;
71
72 pwd_len = strlen(pwd);
73 message_len = nonce_len + pwd_len;
74 message = tds_new(TDS_UCHAR, message_len);
75 if (!message)
76 goto error;
77 memcpy(message, nonce, nonce_len);
78 memcpy(message + nonce_len, pwd, pwd_len);
79
80 em = tds_new(TDS_UCHAR, BN_num_bytes(rsa_get_n(rsa)));
81 if (!em)
82 goto error;
83
84 result = RSA_public_encrypt(message_len, message, em, rsa, RSA_PKCS1_OAEP_PADDING);
85 if (result < 0)
86 goto error;
87
88 free(message);
89 RSA_free(rsa);
90 BIO_free(keybio);
91
92 *em_size = result;
93 return em;
94
95 error:
96 free(message);
97 free(em);
98 RSA_free(rsa);
99 BIO_free(keybio);
100 return NULL;
101 }
102
103 /** @} */
104
105