security_libcrypto.c
Go to the documentation of this file.
1 /*!**********************************************************************
2  *
3  * @copyright Copyright (C) 2016 Siemens Aktiengesellschaft.\n
4  * All rights reserved.
5  *
6  *************************************************************************
7  *
8  * @file security_libcrypto.c
9  * @date Jun 27, 2016
10  * @brief Security libcrypto module implementation file.
11  *
12  ************************************************************************/
13 
14 #include "security_libcrypto.h"
15 #include "memory.h"
16 #include "definitions.h"
17 #include "log_util.h"
18 #include "base64.h"
19 #include "string_util.h"
20 
21 #if (1 == HAVE_OPENSSL_BN_H_)
22 #include <openssl/bn.h>
23 #endif
24 
25 #if (1 == HAVE_OPENSSL_BIO_H_)
26 #include <openssl/bio.h>
27 #endif
28 
29 #if (1 == HAVE_OPENSSL_PEM_H_)
30 #include <openssl/pem.h>
31 #endif
32 
33 #if (1 == HAVE_OPENSSL_RSA_H_)
34 #include <openssl/rsa.h>
35 #endif
36 
37 #if (1 == HAVE_OPENSSL_MD5_H_)
38 #include <openssl/md5.h>
39 #endif
40 
41 #if (1 == HAVE_OPENSSL_SHA_H_)
42 #include <openssl/sha.h>
43 #endif
44 
45 #if (1 == HAVE_OPENSSL_CRYPTO_H_)
46 #include <openssl/crypto.h>
47 #endif
48 
49 #if (1 == HAVE_OPENSSL_RAND_H_)
50 #include <openssl/rand.h>
51 #endif
52 
53 #define KEY_LENGTH_BITS 3072
54 
55 // This function is used for base64 encoding a big number such as RSA modulus, public exponent and private exponent.
56 static E_MCL_ERROR_CODE _base64_encode_big_number(BIGNUM *big_number, char **encoded);
57 
58 // This function is used to get the public key in PEM format from OpenSSL RSA structure.
59 static E_MCL_ERROR_CODE _get_rsa_public_key(RSA *rsa, char **public_key);
60 
61 // This function is used to get the private key in PEM format from OpenSSL RSA structure.
62 static E_MCL_ERROR_CODE _get_rsa_private_key(RSA *rsa, char **private_key);
63 
64 // Memory function wrappers for OpenSSL.
65 static void *_libcrypto_malloc(size_t size, const char *file, int line);
66 static void *_libcrypto_realloc(void *p, size_t size, const char *file, int line);
67 static void _libcrypto_free(void *p, const char *file, int line);
68 
70 {
71  DEBUG_ENTRY("void")
72 
73  CRYPTO_set_mem_functions(_libcrypto_malloc, _libcrypto_realloc, _libcrypto_free);
74 
75  DEBUG_LEAVE("retVal = void");
76 }
77 
79 {
80  DEBUG_ENTRY("const mcl_uint8_t *data = <%p>, mcl_size_t data_size = <%u>, mcl_uint8_t **hash = <%p>, mcl_size_t *hash_size = <%p>", data, data_size, hash, hash_size)
81 
82  *hash_size = 0;
83 
84  // allocate memory to store SHA256 result
85  *hash = MCL_CALLOC(1, SHA256_DIGEST_LENGTH);
86  ASSERT_CODE_MESSAGE(MCL_NULL != *hash, MCL_OUT_OF_MEMORY, "Memory allocation for SHA256 failed!");
87 
88  *hash_size = SHA256_DIGEST_LENGTH;
89 
90  // perform SHA256 calculation
91  MCL_DEBUG("Calculating SHA256 with OpenSSL.");
92  SHA256(data, data_size, *hash);
93 
94  MCL_DEBUG("Calculated SHA256 *hash = <%p>, hash_size = <%u>", *hash, hash_size);
95  DEBUG_LEAVE("retVal = <%d>", MCL_OK);
96  return MCL_OK;
97 }
98 
99 E_MCL_ERROR_CODE security_rsa_sign(char *rsa_key, char *data, mcl_size_t data_size, mcl_uint8_t **signature, mcl_size_t *signature_size)
100 {
101  DEBUG_ENTRY("char *rsa_key = <%s>, char *data = <%s>, mcl_size_t data_size = <%u>, mcl_uint8_t **signature = <%p>, mcl_size_t *signature_size = <%p>", rsa_key, data, data_size, signature, signature_size)
102 
103  E_MCL_ERROR_CODE code = MCL_OK;
104  unsigned int sign_length = 0;
105  BIO* bio;
106  RSA *rsa = MCL_NULL;
107  mcl_uint8_t *hash = MCL_NULL;
108  mcl_size_t hash_size = 0;
109  mcl_bool_t ok;
110 
111  mcl_size_t length = string_util_strlen(rsa_key);
112  bio = BIO_new_mem_buf(rsa_key, (int)length);
113  ASSERT_CODE_MESSAGE(MCL_NULL != bio, MCL_OUT_OF_MEMORY, "Memory can not be allocated for BIO.");
114 
115  rsa = PEM_read_bio_RSAPrivateKey(bio, &rsa, 0, MCL_NULL);
116  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != rsa, BIO_free(bio), MCL_FAIL, "RSA structure can not be generated.");
117 
118  ok = (MCL_NULL != (*signature = MCL_MALLOC(RSA_size(rsa))));
119  ok = ok && (MCL_OK == security_hash_sha256((const mcl_uint8_t*)data, data_size, &hash, &hash_size));
120  ok = ok && (1 == RSA_sign(NID_sha256, hash, (unsigned int)hash_size, *signature, &sign_length, rsa));
121  *signature_size = sign_length;
122 
123  if (MCL_FALSE == ok)
124  {
125  MCL_FREE(*signature);
126  code = MCL_FAIL;
127  }
128 
129  MCL_FREE(hash);
130  RSA_free(rsa);
131  BIO_free(bio);
132 
133  DEBUG_LEAVE("retVal = <%d>", code);
134  return code;
135 }
136 
137 E_MCL_ERROR_CODE security_generate_rsa_key(char **public_key, char **private_key)
138 {
139  DEBUG_ENTRY("char **public_key = <%p>, char **private_key = <%p>", public_key, private_key)
140 
141  E_MCL_ERROR_CODE code = MCL_FAIL;
142  RSA *rsa;
143  BIGNUM *exponent = MCL_NULL;
144  int result = 0;
145 
146  // Allocate for RSA structure.
147  rsa = RSA_new();
148  ASSERT_CODE_MESSAGE(MCL_NULL != rsa, MCL_OUT_OF_MEMORY, "OpenSSL RSA structure can not be allocated.");
149 
150  // Allocate for the public exponent (e).
151  exponent = BN_new();
152  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != exponent, RSA_free(rsa), MCL_OUT_OF_MEMORY, "OpenSSL big number for exponent can not be allocated.");
153 
154  // Set the value of public exponent.
155  BN_set_word(exponent, RSA_F4);
156 
157  // Generate RSA structure containing public/private key pair.
158  result = RSA_generate_key_ex(rsa, KEY_LENGTH_BITS, exponent, MCL_NULL);
159 
160  // Free public exponent.
161  BN_free(exponent);
162 
163  // Get private key.
164  (0 != result) && (code = _get_rsa_private_key(rsa, private_key));
165 
166  // Get public key.
167  (MCL_OK == code) && (code = _get_rsa_public_key(rsa, public_key));
168 
169  if (MCL_OK != code)
170  {
171  MCL_FREE(private_key);
172  MCL_FREE(public_key);
173  }
174  RSA_free(rsa);
175 
176  DEBUG_LEAVE("retVal = <%d>", code);
177  return code;
178 }
179 
180 E_MCL_ERROR_CODE security_rsa_get_modulus_and_exponent(char *public_key, char **modulus, char **exponent)
181 {
182  DEBUG_ENTRY("char *public_key = <%s>, char **modulus = <%p>, char **exponent = <%p>", public_key, modulus, exponent)
183 
184  E_MCL_ERROR_CODE code;
185  RSA *rsa = MCL_NULL;
186  BIGNUM *n;
187  BIGNUM *e;
188  mcl_size_t length = string_util_strlen(public_key);
189  BIO *bio = BIO_new_mem_buf(public_key, (int)length);
190  ASSERT_CODE_MESSAGE(MCL_NULL != bio, MCL_OUT_OF_MEMORY, "Memory can not be allocated for BIO.");
191 
192  rsa = PEM_read_bio_RSA_PUBKEY(bio, &rsa, 0, MCL_NULL);
193  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != rsa, BIO_free(bio), MCL_FAIL, "RSA structure can not be generated.");
194 
195  // Get modulus and exponent.
196  RSA_get0_key(rsa, &n, &e, MCL_NULL);
197 
198  code = _base64_encode_big_number(n, modulus);
199  (MCL_OK == code) && (code = _base64_encode_big_number(e, exponent));
200 
201  if (MCL_OK != code)
202  {
203  MCL_FREE(*modulus);
204  MCL_FREE(*exponent);
205  }
206 
207  RSA_free(rsa);
208  BIO_free(bio);
209 
210  DEBUG_LEAVE("retVal = <%d>", code);
211  return code;
212 }
213 
215 {
216  DEBUG_ENTRY("unsigned char *buffer = <%p>, mcl_size_t size = <%u>", buffer, size)
217 
218  E_MCL_ERROR_CODE code = MCL_FAIL;
219 
220 #if (1 == HAVE_OPENSSL_RAND_H_)
221  if(1 == RAND_bytes(buffer, (int)size))
222  {
223  code = MCL_OK;
224  }
225 #endif
226 
227  DEBUG_LEAVE("retVal = <%d>", code);
228  return code;
229 }
230 
231 static E_MCL_ERROR_CODE _base64_encode_big_number(BIGNUM *big_number, char **encoded)
232 {
233  DEBUG_ENTRY("BIGNUM *big_number = <%p>, char **encoded = <%p>", big_number, encoded)
234 
235  E_MCL_ERROR_CODE code;
236  int binary_length;
237  char *binary;
238  string_t *binary_encoded = MCL_NULL;
239 
240  binary = MCL_MALLOC(BN_num_bytes(big_number));
242 
243  binary_length = BN_bn2bin(big_number, (unsigned char *)binary);
244 
245  code = base64_url_encode((const mcl_uint8_t*)binary, binary_length, &binary_encoded);
246 
247  if (MCL_OK == code)
248  {
249  *encoded = binary_encoded->buffer;
250  }
251 
252  MCL_FREE(binary_encoded);
253  MCL_FREE(binary);
254 
255  DEBUG_LEAVE("retVal = <%d>", code);
256  return code;
257 }
258 
259 static E_MCL_ERROR_CODE _get_rsa_private_key(RSA *rsa, char **private_key)
260 {
261  DEBUG_ENTRY("RSA *rsa = <%p>, char **private_key = <%p>", rsa, private_key)
262 
263  E_MCL_ERROR_CODE code = MCL_OK;
264  BIO *bio;
265  int key_length = 0;
266 
267  bio = BIO_new(BIO_s_mem());
268  ASSERT_CODE_MESSAGE(MCL_NULL != bio, MCL_OUT_OF_MEMORY, "Memory can not allocated for BIO.");
269 
270  if (!PEM_write_bio_RSAPrivateKey(bio, rsa, NULL, NULL, 0, NULL, NULL))
271  {
272  BIO_free_all(bio);
273  MCL_ERROR_RETURN(MCL_FAIL, "Private key can not be written from RSA struct to BIO.");
274  }
275  key_length = BIO_pending(bio);
276 
277  *private_key = MCL_MALLOC(key_length + 1);
278  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != *private_key, BIO_free_all(bio), MCL_OUT_OF_MEMORY, "Memory can not be allocated for private key.");
279 
280  if (key_length != BIO_read(bio, *private_key, key_length))
281  {
282  MCL_DEBUG("Private key can not be read from BIO.");
283  code = MCL_FAIL;
284  MCL_FREE(*private_key);
285  }
286  (*private_key)[key_length] = MCL_NULL_CHAR;
287 
288  BIO_free_all(bio);
289 
290  DEBUG_LEAVE("retVal = <%d>", code);
291  return code;
292 }
293 
294 static E_MCL_ERROR_CODE _get_rsa_public_key(RSA *rsa, char **public_key)
295 {
296  DEBUG_ENTRY("RSA *rsa = <%p>, char **public_key = <%p>", rsa, public_key)
297 
298  E_MCL_ERROR_CODE code = MCL_OK;
299  BIO *bio;
300  int key_length = 0;
301 
302  bio = BIO_new(BIO_s_mem());
303  ASSERT_CODE_MESSAGE(MCL_NULL != bio, MCL_OUT_OF_MEMORY, "Memory can not allocated for BIO.");
304 
305  if (!PEM_write_bio_RSA_PUBKEY(bio, rsa))
306  {
307  BIO_free_all(bio);
308  MCL_ERROR_RETURN(MCL_FAIL, "Public key can not be written from RSA struct to BIO.");
309  }
310  key_length = BIO_pending(bio);
311 
312  *public_key = MCL_MALLOC(key_length + 1);
313  ASSERT_STATEMENT_CODE_MESSAGE(MCL_NULL != *public_key, BIO_free_all(bio), MCL_OUT_OF_MEMORY, "Memory can not be allocated for public key.");
314 
315  if (key_length != BIO_read(bio, *public_key, key_length))
316  {
317  MCL_DEBUG("Public key can not be read from BIO.");
318  code = MCL_FAIL;
319  MCL_FREE(*public_key);
320  }
321  (*public_key)[key_length] = MCL_NULL_CHAR;
322 
323  BIO_free_all(bio);
324 
325  DEBUG_LEAVE("retVal = <%d>", code);
326  return code;
327 }
328 
329 static void *_libcrypto_malloc(size_t size, const char *file, int line)
330 {
331  void* p = MCL_NULL;
332 
333  VERBOSE_ENTRY("size_t size = <%lu>, const char *file = <%s>, int line = <%d>", size, file, line);
334 
335 #if (MCL_LOG_UTIL_LEVEL < MCL_LOG_UTIL_LEVEL_VERBOSE)
336  // Unused parameters.
337  (void) file;
338  (void) line;
339 #endif
340 
341  p = memory_malloc(size);
342 
343  VERBOSE_LEAVE("retVal = <%p>", p);
344  return p;
345 }
346 
347 static void *_libcrypto_realloc(void *p, size_t size, const char *file, int line)
348 {
349  void *memory_reallocated;
350 
351  VERBOSE_ENTRY("void *p = <%p>, size_t size = <%lu>, const char *file = <%s>, int line = <%d>", p, size, file, line);
352 
353 #if (MCL_LOG_UTIL_LEVEL < MCL_LOG_UTIL_LEVEL_VERBOSE)
354  // Unused parameters.
355  (void) file;
356  (void) line;
357 #endif
358 
359  memory_reallocated = memory_realloc(p, size);
360 
361  VERBOSE_LEAVE("retVal = <%p>", memory_reallocated);
362  return memory_reallocated;
363 }
364 
365 static void _libcrypto_free(void *p, const char *file, int line)
366 {
367  VERBOSE_ENTRY("void *p = <%p>, const char *file = <%s>, int line = <%d>", p, file, line);
368 
369 #if (MCL_LOG_UTIL_LEVEL < MCL_LOG_UTIL_LEVEL_VERBOSE)
370  // Unused parameters.
371  (void) file;
372  (void) line;
373 #endif
374 
375  memory_free(p);
376 
377  VERBOSE_LEAVE("retVal = <void>");
378 }
void security_initialize(void)
Internal failure in MCL.
Definition: mcl_common.h:141
Memory module header file.
static E_MCL_ERROR_CODE _get_rsa_public_key(RSA *rsa, char **public_key)
#define VERBOSE_LEAVE(...)
Definition: log_util.h:66
#define DEBUG_LEAVE(...)
Definition: log_util.h:81
E_MCL_ERROR_CODE base64_url_encode(const mcl_uint8_t *data, mcl_size_t data_size, string_t **encoded_data)
Definition: base64.c:112
#define DEBUG_ENTRY(...)
Definition: log_util.h:80
E_MCL_ERROR_CODE security_generate_random_bytes(unsigned char *buffer, mcl_size_t size)
To be used to generate random bytes.
char * buffer
Buffer of string handle.
Definition: string_type.h:45
Security libcrypto module header file.
static E_MCL_ERROR_CODE _get_rsa_private_key(RSA *rsa, char **private_key)
#define MCL_DEBUG(...)
Definition: log_util.h:70
#define MCL_FALSE
MCL bool type.
Definition: mcl_common.h:53
#define MCL_MALLOC(bytes)
Definition: memory.h:120
Log utility module header file.
String utility module implementation file.
E_MCL_ERROR_CODE
MCL Error code definitions. Every function returning an error code uses this enum values...
Definition: mcl_common.h:137
void * memory_malloc(mcl_size_t size)
malloc wrapper
Definition: memory.c:99
#define MCL_FREE(p)
Definition: memory.h:125
static E_MCL_ERROR_CODE _base64_encode_big_number(BIGNUM *big_number, char **encoded)
#define VERBOSE_ENTRY(...)
Definition: log_util.h:65
#define ASSERT_STATEMENT_CODE_MESSAGE(condition, statement, return_code,...)
Definition: definitions.h:121
static void * _libcrypto_realloc(void *p, size_t size, const char *file, int line)
uint8_t mcl_uint8_t
Definition: mcl_common.h:43
#define MCL_CALLOC(count, bytes)
Definition: memory.h:122
E_MCL_ERROR_CODE security_hash_sha256(const mcl_uint8_t *data, mcl_size_t data_size, mcl_uint8_t **hash, mcl_size_t *hash_size)
#define ASSERT_CODE_MESSAGE(condition, return_code,...)
Definition: definitions.h:105
Definitions module header file.
E_MCL_ERROR_CODE security_rsa_get_modulus_and_exponent(char *public_key, char **modulus, char **exponent)
To be used to get the modulus (n) and public exponent (e) parameters of RSA key in Base64 format...
void memory_free(void *p)
free wrapper
Definition: memory.c:129
static void _libcrypto_free(void *p, const char *file, int line)
#define ASSERT_CODE(condition, return_code)
Definition: definitions.h:97
Base64 module header file.
size_t mcl_size_t
Definition: mcl_common.h:38
mcl_uint8_t mcl_bool_t
Definition: mcl_common.h:47
Success.
Definition: mcl_common.h:140
E_MCL_ERROR_CODE security_generate_rsa_key(char **public_key, char **private_key)
To be used to generate the RSA public/private keys.
#define KEY_LENGTH_BITS
Memory allocation fail.
Definition: mcl_common.h:143
#define MCL_NULL
Definition: definitions.h:24
void * memory_realloc(void *p, mcl_size_t bytes)
realloc wrapper
Definition: memory.c:119
mcl_size_t string_util_strlen(const char *buffer)
Standard library strlen wrapper.
Definition: string_util.c:24
E_MCL_ERROR_CODE security_rsa_sign(char *rsa_key, char *data, mcl_size_t data_size, mcl_uint8_t **signature, mcl_size_t *signature_size)
To be used to sign data with RSA key.
#define MCL_NULL_CHAR
Definition: definitions.h:26
static void * _libcrypto_malloc(size_t size, const char *file, int line)
#define MCL_ERROR_RETURN(return_value,...)
Definition: definitions.h:69