Allow SHA1_Init()/SHA1_Update() to fail if OpenSSL version >= 1.0
[strongswan.git] / src / libstrongswan / plugins / openssl / openssl_sha1_prf.c
1 /*
2 * Copyright (C) 2010 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <openssl/opensslconf.h>
17
18 #ifndef OPENSSL_NO_SHA1
19
20 #include "openssl_sha1_prf.h"
21
22 #include <openssl/sha.h>
23
24 typedef struct private_openssl_sha1_prf_t private_openssl_sha1_prf_t;
25
26 /**
27 * Private data of an openssl_sha1_prf_t object.
28 */
29 struct private_openssl_sha1_prf_t {
30
31 /**
32 * Public openssl_sha1_prf_t interface.
33 */
34 openssl_sha1_prf_t public;
35
36 /**
37 * SHA1 context
38 */
39 SHA_CTX ctx;
40 };
41
42 METHOD(prf_t, get_bytes, bool,
43 private_openssl_sha1_prf_t *this, chunk_t seed, u_int8_t *bytes)
44 {
45 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
46 if (!SHA1_Update(&this->ctx, seed.ptr, seed.len))
47 {
48 return FALSE;
49 }
50 #else /* OPENSSL_VERSION_NUMBER < 1.0 */
51 SHA1_Update(&this->ctx, seed.ptr, seed.len);
52 #endif
53
54 if (bytes)
55 {
56 u_int32_t *hash = (u_int32_t*)bytes;
57
58 hash[0] = htonl(this->ctx.h0);
59 hash[1] = htonl(this->ctx.h1);
60 hash[2] = htonl(this->ctx.h2);
61 hash[3] = htonl(this->ctx.h3);
62 hash[4] = htonl(this->ctx.h4);
63 }
64
65 return TRUE;
66 }
67
68 METHOD(prf_t, get_block_size, size_t,
69 private_openssl_sha1_prf_t *this)
70 {
71 return HASH_SIZE_SHA1;
72 }
73
74 METHOD(prf_t, allocate_bytes, bool,
75 private_openssl_sha1_prf_t *this, chunk_t seed, chunk_t *chunk)
76 {
77 if (chunk)
78 {
79 *chunk = chunk_alloc(HASH_SIZE_SHA1);
80 return get_bytes(this, seed, chunk->ptr);
81 }
82 return get_bytes(this, seed, NULL);
83 }
84
85 METHOD(prf_t, get_key_size, size_t,
86 private_openssl_sha1_prf_t *this)
87 {
88 return HASH_SIZE_SHA1;
89 }
90
91 METHOD(prf_t, set_key, bool,
92 private_openssl_sha1_prf_t *this, chunk_t key)
93 {
94 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
95 if (!SHA1_Init(&this->ctx))
96 {
97 return FALSE;
98 }
99 #else /* OPENSSL_VERSION_NUMBER < 1.0 */
100 SHA1_Init(&this->ctx);
101 #endif
102
103 if (key.len % 4)
104 {
105 return FALSE;
106 }
107 if (key.len >= 4)
108 {
109 this->ctx.h0 ^= untoh32(key.ptr);
110 }
111 if (key.len >= 8)
112 {
113 this->ctx.h1 ^= untoh32(key.ptr + 4);
114 }
115 if (key.len >= 12)
116 {
117 this->ctx.h2 ^= untoh32(key.ptr + 8);
118 }
119 if (key.len >= 16)
120 {
121 this->ctx.h3 ^= untoh32(key.ptr + 12);
122 }
123 if (key.len >= 20)
124 {
125 this->ctx.h4 ^= untoh32(key.ptr + 16);
126 }
127 return TRUE;
128 }
129
130 METHOD(prf_t, destroy, void,
131 private_openssl_sha1_prf_t *this)
132 {
133 free(this);
134 }
135
136 /**
137 * See header
138 */
139 openssl_sha1_prf_t *openssl_sha1_prf_create(pseudo_random_function_t algo)
140 {
141 private_openssl_sha1_prf_t *this;
142
143 if (algo != PRF_KEYED_SHA1)
144 {
145 return NULL;
146 }
147
148 INIT(this,
149 .public = {
150 .prf = {
151 .get_block_size = _get_block_size,
152 .get_bytes = _get_bytes,
153 .allocate_bytes = _allocate_bytes,
154 .get_key_size = _get_key_size,
155 .set_key = _set_key,
156 .destroy = _destroy,
157 },
158 },
159 );
160
161 return &this->public;
162 }
163
164 #endif /* OPENSSL_NO_SHA1 */