summaryrefslogtreecommitdiffstats
path: root/task1/security.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'task1/security.cpp')
-rw-r--r--task1/security.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/task1/security.cpp b/task1/security.cpp
new file mode 100644
index 0000000..d092be0
--- /dev/null
+++ b/task1/security.cpp
@@ -0,0 +1,330 @@
1/**
2 * Wrapper for OpenSSL cryptographic functions.
3 * @author SE/Linux Team <se-linux@inso.tuwien.ac.at>
4 */
5
6#include "security.h"
7
8#include <errno.h>
9#include <iostream>
10#include <stdio.h>
11#include <string.h>
12#include <sstream>
13
14#include <openssl/rsa.h>
15#include <openssl/evp.h>
16#include <openssl/objects.h>
17#include <openssl/x509.h>
18#include <openssl/err.h>
19#include <openssl/pem.h>
20#include <openssl/ssl.h>
21
22//! Implementation of the Security interface.
23//! We didn't put this declaration into the public header, beacause it
24//! contains OpenSSL related IMPLEMENTATION DETAILS.
25class SecurityImpl : public Security {
26
27 public:
28
29 virtual void sign(
30 const std::string& privateKeyFile,
31 const ByteStream& data,
32 ByteStream& output
33 );
34
35 virtual void verifySignature(
36 const std::string& certificateFile,
37 const ByteStream& data,
38 const ByteStream& signature
39 );
40
41 virtual void encryptPublic(
42 const std::string& certificateFile,
43 const ByteStream& data,
44 ByteStream& iv,
45 ByteStream& ek,
46 ByteStream& output
47 );
48
49 virtual void decryptPrivate(
50 const std::string& privateKeyFile,
51 const ByteStream& data,
52 const ByteStream& iv,
53 const ByteStream& ek,
54 ByteStream& output
55 );
56
57 virtual std::string getCommonName(
58 const std::string& certificateFile
59 );
60
61 private:
62
63 //! Opens the given file.
64 //! @throws SecurityException on error.
65 FILE *openFile(const std::string& file);
66
67 //! Throws an SecurityException containing the last OpenSSL error.
68 void throwSslError();
69
70 //! Reads a private key from the given file.
71 //! @throws SecurityException on error.
72 EVP_PKEY* readPrivKey(const std::string& file);
73
74 //! Reads a public key from the given certificate file.
75 //! @throws SecurityException on error.
76 EVP_PKEY* readPubKey(const std::string& file);
77
78 //! Reads a X509 certificate from the given certificate file.
79 //! @throws SecurityException on error.
80 X509 *readX509(const std::string& file);
81};
82
83// -----------------------------------------------------------------------------
84// SecurityException
85// -----------------------------------------------------------------------------
86
87SecurityException::SecurityException(const std::string& what) :
88 _what(what)
89{
90}
91
92// -----------------------------------------------------------------------------
93// Security
94// -----------------------------------------------------------------------------
95
96Security& Security::instance() {
97 if (_instance == 0) {
98 _instance = new SecurityImpl();
99 }
100 return *_instance;
101}
102
103Security *Security::_instance = 0;
104
105// -----------------------------------------------------------------------------
106// SecurityImpl
107// -----------------------------------------------------------------------------
108
109FILE *SecurityImpl::openFile(const std::string& file) {
110 FILE *ret = fopen(file.c_str(), "r");
111 if (ret == NULL) {
112 std::ostringstream os;
113 os << "Could not open file " << file << ": " << strerror(errno);
114 throw SecurityException(os.str());
115 }
116 return ret;
117}
118
119void SecurityImpl::throwSslError() {
120 ERR_print_errors_fp(stderr);
121 throw SecurityException("ssl error");
122}
123
124EVP_PKEY* SecurityImpl::readPrivKey(const std::string& file) {
125 FILE *f = NULL;
126 EVP_PKEY *ret = NULL;
127
128 f = openFile(file);
129 ret = PEM_read_PrivateKey(f, NULL, NULL, NULL);
130 fclose(f);
131
132 if (! ret) {
133 throwSslError();
134 }
135
136 return ret;
137}
138
139X509 *SecurityImpl::readX509(const std::string& file) {
140 FILE *f = openFile(file);
141 X509 *ret = PEM_read_X509(f, NULL, NULL, NULL);
142 fclose(f);
143
144 if (!ret) {
145 throwSslError();
146 }
147 return ret;
148}
149
150void SecurityImpl::sign(
151 const std::string& privateKeyFile,
152 const ByteStream& data,
153 ByteStream& output
154 ) {
155 EVP_PKEY *priv = readPrivKey(privateKeyFile);
156 EVP_MD_CTX ctx;
157
158 EVP_SignInit(&ctx, EVP_sha1());
159 EVP_SignUpdate(&ctx, &data[0], data.size());
160 output.resize(EVP_PKEY_size(priv));
161 unsigned int len = output.size();
162 int err = EVP_SignFinal(&ctx, &output[0], &len, priv);
163
164 EVP_PKEY_free(priv);
165 EVP_MD_CTX_cleanup(&ctx);
166
167 if (err == 1) {
168 output.resize(len);
169 } else {
170 throwSslError();
171 }
172}
173
174void SecurityImpl::verifySignature(
175 const std::string& certificateFile,
176 const ByteStream& data,
177 const ByteStream& signature
178 ) {
179 X509 *x509 = readX509(certificateFile);
180 EVP_PKEY *pub = X509_get_pubkey(x509);
181 bool ok = true;
182 int err;
183
184 if (pub == NULL) {
185 ok = false;
186 goto failout;
187 }
188
189 EVP_MD_CTX ctx;
190 EVP_VerifyInit(&ctx, EVP_sha1());
191 EVP_VerifyUpdate(&ctx, &data[0], data.size());
192 err = EVP_VerifyFinal(&ctx, const_cast<unsigned char *>(&signature[0]), signature.size(), pub);
193
194 if (err != 1) {
195 ok = false;
196 goto failout;
197 }
198
199failout:
200
201 if (pub) EVP_PKEY_free(pub);
202 if (x509) X509_free(x509);
203 if (! ok) throwSslError();
204}
205
206void SecurityImpl::encryptPublic(
207 const std::string& certificateFile,
208 const ByteStream& data,
209 ByteStream& iv,
210 ByteStream& ek,
211 ByteStream& output
212 ) {
213 X509 *x509 = readX509(certificateFile);
214 EVP_PKEY *pub = X509_get_pubkey(x509);
215 bool ok = true;
216 int len, len2;
217
218 const EVP_CIPHER *cipher = EVP_aes_256_cbc();
219 EVP_CIPHER_CTX ctx;
220
221 ek.resize(EVP_PKEY_size(pub));
222 int ekl = ek.size();
223 Byte *ek2 = &ek[0];
224
225 iv.resize(EVP_CIPHER_iv_length(cipher));
226
227 if (! EVP_SealInit(&ctx, cipher, &ek2, &ekl, &iv[0], &pub, 1)) {
228 ok = false;
229 goto failout;
230 }
231
232 ek.resize(ekl);
233
234 output.resize(
235 data.size() + EVP_CIPHER_block_size(cipher) - 1 + // for update
236 EVP_CIPHER_block_size(cipher) // for final
237 );
238 len = output.size();
239
240 if (! EVP_SealUpdate(&ctx, &output[0], &len, &data[0], data.size())) {
241 ok = false;
242 goto failout;
243 }
244 len2 = output.size() - len;
245
246 if (! EVP_SealFinal(&ctx, &output[len], &len2)) {
247 ok = false;
248 goto failout;
249 }
250 output.resize(len + len2);
251
252failout:
253
254 if (pub) EVP_PKEY_free(pub);
255 if (x509) X509_free(x509);
256 if (! ok) throwSslError();
257}
258
259void SecurityImpl::decryptPrivate(
260 const std::string& privateKeyFile,
261 const ByteStream& data,
262 const ByteStream& iv,
263 const ByteStream& ek,
264 ByteStream& output
265 ) {
266 EVP_PKEY *priv = readPrivKey(privateKeyFile);
267
268 const EVP_CIPHER *cipher = EVP_aes_256_cbc();
269 EVP_CIPHER_CTX ctx;
270 int len, len2;
271 bool ok = true;
272
273 output.resize(data.size() + EVP_CIPHER_block_size(cipher));
274
275 if (!EVP_OpenInit(
276 &ctx, cipher,
277 const_cast<unsigned char *>(&ek[0]), ek.size(),
278 const_cast<unsigned char *>(&iv[0]),
279 priv
280 )) {
281 ok = false;
282 goto failout;
283 }
284 if (!EVP_OpenUpdate(&ctx, &output[0], &len, &data[0], data.size())) {
285 ok = false;
286 goto failout;
287 }
288 if (!EVP_OpenFinal(&ctx, &output[len], &len2)) {
289 ok = false;
290 goto failout;
291 }
292
293 output.resize(len + len2);
294
295failout:
296
297 if (priv) EVP_PKEY_free(priv);
298 if (!ok) throwSslError();
299}
300
301std::string SecurityImpl::getCommonName(
302 const std::string& certificateFile
303 ) {
304 X509 *x509 = readX509(certificateFile);
305 X509_NAME *subj = 0;
306 char data[256];
307 bool ok = true;
308
309 subj = X509_get_subject_name(x509);
310
311 if (subj == 0) {
312 ok = false;
313 goto failout;
314 }
315
316 if (! X509_NAME_get_text_by_NID(subj, NID_commonName, data, sizeof(data))) {
317 ok = false;
318 goto failout;
319 }
320
321failout:
322
323 X509_free(x509);
324
325 if (!ok) {
326 throwSslError();
327 }
328 return data;
329
330}