Line data Source code
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 : #include <openssl/rsa.h>
25 :
26 : /**
27 : * \ingroup libtds
28 : * \defgroup auth Authentication
29 : * Functions for handling authentication.
30 : */
31 :
32 : /**
33 : * \addtogroup auth
34 : * @{
35 : */
36 :
37 : #ifndef HAVE_OPENSSL
38 : #error HAVE_OPENSSL not defines, this file should not be included
39 : #endif
40 :
41 : static void *
42 5 : tds5_rsa_encrypt(const void *pem_key, size_t pem_key_len, const void *nonce, size_t nonce_len, const char *pwd, size_t *em_size)
43 : {
44 5 : void *ret = NULL;
45 5 : EVP_PKEY *key = NULL;
46 5 : EVP_PKEY_CTX *ctx = NULL;
47 : BIO *keybio;
48 :
49 : #if OPENSSL_VERSION_NUMBER < 0x3000000FL
50 5 : RSA *rsa = NULL;
51 : #endif
52 :
53 5 : uint8_t *message = NULL;
54 : size_t message_len, pwd_len;
55 5 : uint8_t *em = NULL;
56 :
57 5 : keybio = BIO_new_mem_buf((void *) pem_key, pem_key_len);
58 5 : if (keybio == NULL)
59 : goto error;
60 :
61 : #if OPENSSL_VERSION_NUMBER < 0x3000000FL
62 : /* Old OpenSSL versions seem to not like RSA public key format if PEM_read_bio_PUBKEY is used */
63 5 : key = EVP_PKEY_new();
64 5 : if (!key)
65 : goto error;
66 :
67 5 : rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
68 5 : if (!rsa)
69 : goto error;
70 :
71 5 : EVP_PKEY_set1_RSA(key, rsa);
72 : #else
73 : key = PEM_read_bio_PUBKEY(keybio, &key, NULL, NULL);
74 : if (!key)
75 : goto error;
76 : #endif
77 :
78 5 : pwd_len = strlen(pwd);
79 5 : message_len = nonce_len + pwd_len;
80 5 : message = tds_new(uint8_t, message_len);
81 5 : if (!message)
82 : goto error;
83 5 : memcpy(message, nonce, nonce_len);
84 5 : memcpy(message + nonce_len, pwd, pwd_len);
85 :
86 5 : *em_size = EVP_PKEY_size(key);
87 5 : em = tds_new(uint8_t, *em_size);
88 5 : if (!em)
89 : goto error;
90 :
91 5 : ctx = EVP_PKEY_CTX_new(key, NULL);
92 5 : if (!ctx)
93 : goto error;
94 5 : if (EVP_PKEY_encrypt_init(ctx) <= 0
95 5 : || EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, RSA_PKCS1_OAEP_PADDING, NULL) <= 0)
96 : goto error;
97 :
98 5 : if (EVP_PKEY_encrypt(ctx, em, em_size, message, message_len) <= 0)
99 : goto error;
100 :
101 5 : ret = em;
102 :
103 5 : error:
104 : #if OPENSSL_VERSION_NUMBER < 0x3000000FL
105 5 : RSA_free(rsa);
106 : #endif
107 5 : EVP_PKEY_CTX_free(ctx);
108 5 : free(message);
109 5 : if (!ret)
110 0 : free(em);
111 5 : EVP_PKEY_free(key);
112 5 : BIO_free(keybio);
113 5 : return ret;
114 : }
115 :
116 : /** @} */
|