FreeTDS API
sec_negotiate_openssl.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 <openssl/rand.h>
21 #include <openssl/bio.h>
22 #include <openssl/pem.h>
23 #include <openssl/err.h>
24 #include <openssl/rsa.h>
25 
37 #ifndef HAVE_OPENSSL
38 #error HAVE_OPENSSL not defines, this file should not be included
39 #endif
40 
41 static void *
42 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  void *ret = NULL;
45  EVP_PKEY *key = NULL;
46  EVP_PKEY_CTX *ctx = NULL;
47  BIO *keybio;
48 
49 #if OPENSSL_VERSION_NUMBER < 0x3000000FL
50  RSA *rsa = NULL;
51 #endif
52 
53  uint8_t *message = NULL;
54  size_t message_len, pwd_len;
55  uint8_t *em = NULL;
56 
57  keybio = BIO_new_mem_buf((void *) pem_key, pem_key_len);
58  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  key = EVP_PKEY_new();
64  if (!key)
65  goto error;
66 
67  rsa = PEM_read_bio_RSAPublicKey(keybio, &rsa, NULL, NULL);
68  if (!rsa)
69  goto error;
70 
71  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  pwd_len = strlen(pwd);
79  message_len = nonce_len + pwd_len;
80  message = tds_new(uint8_t, message_len);
81  if (!message)
82  goto error;
83  memcpy(message, nonce, nonce_len);
84  memcpy(message + nonce_len, pwd, pwd_len);
85 
86  *em_size = EVP_PKEY_size(key);
87  em = tds_new(uint8_t, *em_size);
88  if (!em)
89  goto error;
90 
91  ctx = EVP_PKEY_CTX_new(key, NULL);
92  if (!ctx)
93  goto error;
94  if (EVP_PKEY_encrypt_init(ctx) <= 0
95  || 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  if (EVP_PKEY_encrypt(ctx, em, em_size, message, message_len) <= 0)
99  goto error;
100 
101  ret = em;
102 
103  error:
104 #if OPENSSL_VERSION_NUMBER < 0x3000000FL
105  RSA_free(rsa);
106 #endif
107  EVP_PKEY_CTX_free(ctx);
108  free(message);
109  if (!ret)
110  free(em);
111  EVP_PKEY_free(key);
112  BIO_free(keybio);
113  return ret;
114 }
115