Branch data Line data Source code
1 : : /* zxid/zxcrypto.c - Glue for cryptographical functions
2 : : * Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
3 : : * Author: Sampo Kellomaki (sampo@iki.fi)
4 : : * This is confidential unpublished proprietary source code of the author.
5 : : * NO WARRANTY, not even implied warranties. Contains trade secrets.
6 : : * Distribution prohibited unless authorized in writing.
7 : : * Licensed under Apache License 2.0, see file COPYING.
8 : : * $Id: zxcrypto.c,v 1.10 2009-11-24 23:53:40 sampo Exp $
9 : : *
10 : : * 7.10.2008, added documentation --Sampo
11 : : * 29.8.2009, added zxid_mk_self_signed_cert() --Sampo
12 : : */
13 : :
14 : : #include "platform.h" /* needed on Win32 for snprintf() et al. */
15 : :
16 : : #include <zx/errmac.h>
17 : : #include <zx/zx.h>
18 : : #include <zx/zxid.h>
19 : : #include <zx/zxidutil.h>
20 : : #include <zx/c/zx-sa-data.h>
21 : : #include <string.h>
22 : : #include <sys/stat.h> /* umask(2) */
23 : :
24 : : #ifdef USE_OPENSSL
25 : : #include <openssl/evp.h>
26 : : #include <openssl/md5.h>
27 : : #include <openssl/hmac.h>
28 : : #include <openssl/rand.h>
29 : : #include <openssl/x509.h>
30 : : #include <openssl/x509v3.h>
31 : : #include <openssl/rsa.h>
32 : : #include <openssl/pem.h>
33 : : #endif
34 : :
35 : : #if 0
36 : : /* Called by: */
37 : : struct zx_str* zx_hmac_sha1(struct zx_ctx* c, struct zx_str* key, struct zx_str* ss) {
38 : : HMAC(EVP_sha1(), key->s, key->len, ss->s, ss->len, md, mdlen);
39 : :
40 : : EVP_CIPHER_CTX *ctx;
41 : : EVP_CIPHER *type = EVP_des_cbc();
42 : :
43 : : int EVP_SealInit(ctx, type, char **ek, int *ekl, char *iv, EVP_PKEY **pubk, int npubk);
44 : : int EVP_SealUpdate(ctx, unsigned char *out, int *outl, unsigned char *in, int inl);
45 : : int EVP_SealFinal(ctx, unsigned char *out, int *outl);
46 : : }
47 : :
48 : : /* Following are macros in openssl headers so we need to define wrapper functions. */
49 : :
50 : : /* Called by: */
51 : : int zx_EVP_CIPHER_key_length(const EVP_CIPHER* cipher) { return EVP_CIPHER_key_length(cipher); }
52 : : int zx_EVP_CIPHER_iv_length(const EVP_CIPHER* cipher) { return EVP_CIPHER_iv_length(cipher); }
53 : : int zx_EVP_CIPHER_block_size(const EVP_CIPHER* cipher) { return EVP_CIPHER_block_size(cipher); }
54 : : #endif
55 : :
56 : : /*() zx_raw_digest2() computes a message digest over two items. The result
57 : : * is placed in buffer md, which must already be of length sufficient for
58 : : * the digest. md will not be nul terminated (and will usually have binary
59 : : * data). Possible algos: SHA1 */
60 : :
61 : : char* zx_raw_digest2(struct zx_ctx* c, char* md, char* const algo, int len, const char* s, int len2, const char* s2)
62 : 74 : {
63 : 74 : char* where = "start";
64 : : const EVP_MD* evp_digest;
65 : : EVP_MD_CTX ctx;
66 : 74 : OpenSSL_add_all_digests();
67 : 74 : EVP_MD_CTX_init(&ctx);
68 : 74 : evp_digest = EVP_get_digestbyname(algo);
69 [ - + ]: 74 : if (!evp_digest) {
70 : 0 : ERR("Digest algo name(%s) not recognized by the crypto library (OpenSSL)", algo);
71 : 0 : return 0;
72 : : }
73 : :
74 [ - + ]: 74 : if (!EVP_DigestInit_ex(&ctx, evp_digest, 0 /* engine */)) {
75 : 0 : where = "EVP_DigestInit_ex()";
76 : 0 : goto sslerr;
77 : : }
78 : :
79 [ + - + - ]: 74 : if (len && s) {
80 [ - + ]: 74 : if (!EVP_DigestUpdate(&ctx, s, len)) {
81 : 0 : where = "EVP_DigestUpdate()";
82 : 0 : goto sslerr;
83 : : }
84 : : }
85 : :
86 [ + - + - ]: 74 : if (len2 && s2) {
87 [ - + ]: 74 : if (!EVP_DigestUpdate(&ctx, s2, len2)) {
88 : 0 : where = "EVP_DigestUpdate() 2";
89 : 0 : goto sslerr;
90 : : }
91 : : }
92 : :
93 [ - + ]: 74 : if(!EVP_DigestFinal_ex(&ctx, (unsigned char*)md, 0)) {
94 : 0 : where = "EVP_DigestFinal_ex()";
95 : 0 : goto sslerr;
96 : : }
97 : 74 : EVP_MD_CTX_cleanup(&ctx);
98 : 74 : return md;
99 : :
100 : 0 : sslerr:
101 : 0 : zx_report_openssl_error(where);
102 : 0 : EVP_MD_CTX_cleanup(&ctx);
103 : 0 : return 0;
104 : : }
105 : :
106 : : /*() zx_EVP_DecryptFinal_ex() is a drop-in replacement for OpenSSL EVP_DecryptFinal_ex.
107 : : * It performs XML Enc compatible padding check. See OpenSSL bug 1067
108 : : * http://rt.openssl.org/Ticket/Display.html?user=guest&;pass=guest&id=1067 */
109 : :
110 : : /* Called by: zx_raw_cipher */
111 : 105 : int zx_EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl) {
112 : : int i,n;
113 : : unsigned int b;
114 : :
115 : 105 : *outl=0;
116 : 105 : b=ctx->cipher->block_size;
117 [ + - ]: 105 : if (b > 1) {
118 [ + - - + ]: 105 : if (ctx->buf_len || !ctx->final_used) {
119 : : //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_WRONG_FINAL_BLOCK_LENGTH);
120 : 0 : return(0);
121 : : }
122 [ - + # # ]: 105 : ASSERTOP(b, <=, sizeof ctx->final);
123 : 105 : n=ctx->final[b-1];
124 [ + - + + ]: 105 : if (n == 0 || n > (int)b) {
125 : : //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_BAD_DECRYPT);
126 : 2 : return(0);
127 : : }
128 : :
129 : : /* The padding used in XML Enc does not follow RFC 1423
130 : : * and is not supported by OpenSSL. The last padding byte
131 : : * is checked, but all other padding bytes are ignored
132 : : * and trimmed.
133 : : *
134 : : * [XMLENC] D. Eastlake, ed., XML Encryption Syntax and
135 : : * Processing, W3C Recommendation 10. Dec. 2002,
136 : : * www.w3.org/TR/2002/REC-xmlenc-core-20021210">http://www.w3.org/TR/2002/REC-xmlenc-core-20021210 */
137 [ - + ]: 103 : if (ctx->final[b-1] != n) {
138 : : //EVPerr(EVP_F_EVP_DECRYPTFINAL_EX,EVP_R_BAD_DECRYPT);
139 : 0 : return(0);
140 : : }
141 : 103 : n=ctx->cipher->block_size-n;
142 [ + + ]: 758 : for (i=0; i<n; i++)
143 : 655 : out[i]=ctx->final[i];
144 : 103 : *outl=n;
145 : : } else
146 : 0 : *outl=0;
147 : 103 : return 1;
148 : : }
149 : :
150 : : //#define ZX_DEFAULT_IV "012345678901234567890123456789012345678901234567890123456789" /* 60 */
151 : : #define ZX_DEFAULT_IV "ZX_DEFAULT_IV ZXID.ORG SAML 2.0 and Liberty ID-WSF by Sampo." /* 60 */
152 : :
153 : : /*() zx_raw_cipher() can encrypt and decrypt, based on encflag, using symmetic cipher algo.
154 : : * If encflag (==1) indicates encryption, the initialization vector will be prepended. */
155 : :
156 : : /* Called by: zxenc_symkey_dec x4, zxenc_symkey_enc, zxid_psobj_dec, zxid_psobj_enc */
157 : : struct zx_str* zx_raw_cipher(struct zx_ctx* c, const char* algo, int encflag, struct zx_str* key, int len, const char* s, int iv_len, const char* iv)
158 : 1134 : {
159 : : const char* ivv;
160 : 1134 : char* where = "start";
161 : : struct zx_str* out;
162 : : int outlen, tmplen, alloclen;
163 : : const EVP_CIPHER* evp_cipher;
164 : : EVP_CIPHER_CTX ctx;
165 : 1134 : OpenSSL_add_all_algorithms();
166 : 1134 : EVP_CIPHER_CTX_init(&ctx);
167 : 1134 : evp_cipher = EVP_get_cipherbyname(algo);
168 [ - + ]: 1134 : if (!evp_cipher) {
169 : 0 : ERR("Cipher algo name(%s) not recognized by the crypto library (OpenSSL)", algo);
170 : 0 : return 0;
171 : : }
172 : :
173 : 1134 : tmplen = EVP_CIPHER_iv_length(evp_cipher);
174 [ + - ]: 1134 : if (tmplen) {
175 [ + + ]: 1134 : if (iv) {
176 [ - + ]: 105 : if (iv_len != tmplen) {
177 : 0 : goto clean;
178 : : }
179 : 105 : ivv = iv;
180 : : } else {
181 : 1029 : ivv = ZX_DEFAULT_IV;
182 : : ASSERTOP(EVP_MAX_IV_LENGTH, <=, sizeof(ZX_DEFAULT_IV));
183 : : }
184 : : } else
185 : 0 : ivv = 0;
186 : :
187 : 1134 : alloclen = EVP_CIPHER_block_size(evp_cipher);
188 : 1134 : alloclen = len + alloclen + alloclen; /* bit pessimistic, but man EVP_CipherInit is ambiguous about the actual size needed. */
189 [ + + ]: 1134 : if (encflag)
190 : 1029 : alloclen += iv_len;
191 : :
192 : 1134 : out = zx_new_len_str(c, alloclen);
193 [ + - ]: 1134 : if (!out) goto clean;
194 [ + + ]: 1134 : if (encflag)
195 : 1029 : memcpy(out->s, ivv, iv_len);
196 : : else
197 : 105 : iv_len = 0; /* When decrypting, the iv has already been stripped. */
198 : :
199 [ - + ]: 1134 : if (!EVP_CipherInit_ex(&ctx, evp_cipher, 0 /* engine */, (unsigned char*)key->s, (unsigned char*)ivv, encflag)) {
200 : 0 : where = "EVP_CipherInit_ex()";
201 : 0 : goto sslerr;
202 : : }
203 : :
204 [ - + ]: 1134 : if (!EVP_CIPHER_CTX_set_key_length(&ctx, key->len)) {
205 : 0 : where = "wrong key length for algorithm (block ciphers only accept keys of determined length)";
206 : 0 : goto sslerr;
207 : : }
208 : :
209 [ - + ]: 1134 : if (!EVP_CipherUpdate(&ctx, (unsigned char*)out->s + iv_len, &outlen, (unsigned char*)s, len)) { /* Actual crypto happens here */
210 : 0 : where = "EVP_CipherUpdate()";
211 : 0 : goto sslerr;
212 : : }
213 : :
214 [ - + # # ]: 1134 : ASSERTOP(outlen + iv_len, <=, alloclen);
215 : :
216 : : #if 0
217 : : if(!EVP_CipherFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) { /* Append final block */
218 : : where = "EVP_CipherFinal_ex()";
219 : : goto sslerr;
220 : : }
221 : : #else
222 : : /* Patch from Eric Rybski <rybskej@yahoo.com> */
223 [ + + ]: 1134 : if (encflag) {
224 [ - + ]: 1029 : if(!EVP_CipherFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) { /* Append final block */
225 : 0 : where = "EVP_CipherFinal_ex()";
226 : 0 : goto sslerr;
227 : : }
228 : : } else {
229 : : /* Perform our own padding check, as XML Enc is not guaranteed compatible
230 : : * with OpenSSL & RFC 1423. See OpenSSL bug 1067
231 : : * http://rt.openssl.org/Ticket/Display.html?user=guest&;pass=guest&id=1067 */
232 : 105 : EVP_CIPHER_CTX_set_padding(&ctx, 0);
233 [ + + ]: 105 : if(!zx_EVP_DecryptFinal_ex(&ctx, (unsigned char*)out->s + iv_len + outlen, &tmplen)) { /* Append final block */
234 : 2 : where = "zx_EVP_DecryptFinal_ex()";
235 : 2 : goto sslerr;
236 : : }
237 : : }
238 : : #endif
239 : 1132 : EVP_CIPHER_CTX_cleanup(&ctx);
240 : :
241 : 1132 : outlen += tmplen;
242 [ - + # # ]: 1132 : ASSERTOP(outlen + iv_len, <=, alloclen);
243 : 1132 : out->len = outlen + iv_len;
244 : 1132 : out->s[outlen + iv_len] = 0; /* nul term */
245 : 1132 : return out;
246 : :
247 : 2 : sslerr:
248 : 2 : zx_report_openssl_error(where);
249 : 2 : clean:
250 : 2 : EVP_CIPHER_CTX_cleanup(&ctx);
251 : 2 : return 0;
252 : : }
253 : :
254 : : /*() RSA public key encryption. See zx_get_rsa_pub_from_cert() for
255 : : * a way to obtain public key data structure.
256 : : * N.B. This function +only+ does the public key part. It does not
257 : : * perform combined enc-session-key-with-pub-key-and-then-data-with-session-key
258 : : * operation, though this function could be used as a component to implement
259 : : * such a system.
260 : : *
261 : : * This is considered a low level function. See zxenc_pubkey_enc() for a higher level solution. */
262 : :
263 : : /* Called by: zxenc_pubkey_enc x2 */
264 : : struct zx_str* zx_rsa_pub_enc(struct zx_ctx* c, struct zx_str* plain, RSA* rsa_pkey, int pad)
265 : 957 : {
266 : : struct zx_str* ciphered;
267 : 957 : int ret, siz = RSA_size(rsa_pkey);
268 [ + - - - ]: 957 : switch (pad) {
269 : : case RSA_PKCS1_PADDING:
270 : : case RSA_SSLV23_PADDING:
271 [ - + ]: 957 : if (plain->len > (siz-11))
272 : 0 : ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz-11, plain->len);
273 [ + + - + ]: 957 : D("RSA_PKCS1_PADDING %d", pad);
274 : 957 : break;
275 : : case RSA_NO_PADDING:
276 [ # # ]: 0 : if (plain->len > siz)
277 : 0 : ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz, plain->len);
278 : 0 : break;
279 : : case RSA_PKCS1_OAEP_PADDING:
280 [ # # ]: 0 : if (plain->len > (siz-41))
281 : 0 : ERR("Too much data for RSA key: can=%d, you have %d bytes.\n", siz-41, plain->len);
282 : 0 : break;
283 [ # # # # ]: 0 : default: D("Illegal padding(%d). See `man 3 rsa'\n",pad);
284 : : }
285 : :
286 : 957 : ciphered = zx_new_len_str(c, siz);
287 [ - + ]: 957 : if (!ciphered)
288 : 0 : return 0;
289 : 957 : ret = RSA_public_encrypt(plain->len, (unsigned char*)plain->s, (unsigned char*)ciphered->s, rsa_pkey, pad);
290 [ - + ]: 957 : if (siz != ret) {
291 [ # # # # ]: 0 : D("RSA pub enc wrong ret=%d siz=%d\n",ret,siz);
292 : 0 : zx_report_openssl_error("zx_pub_encrypt_rsa fail (${ret})");
293 : 0 : return 0;
294 : : }
295 [ - + # # ]: 957 : ASSERTOP(ret, <=, siz);
296 : 957 : ciphered->len = ret;
297 : 957 : ciphered->s[ret] = 0;
298 : 957 : return ciphered;
299 : : }
300 : :
301 : : /*() RSA public key decryption. See zx_get_rsa_pub_from_cert() for
302 : : * a way to obtain public key data structure. */
303 : :
304 : : /* Called by: */
305 : : struct zx_str* zx_rsa_pub_dec(struct zx_ctx* c, struct zx_str* ciphered, RSA* rsa_pkey, int pad)
306 : 0 : {
307 : : struct zx_str* plain;
308 : 0 : int ret, siz = RSA_size(rsa_pkey);
309 : 0 : plain = zx_new_len_str(c, siz);
310 [ # # ]: 0 : if (!plain)
311 : 0 : return 0;
312 : 0 : ret = RSA_public_decrypt(ciphered->len, (unsigned char*)ciphered->s, (unsigned char*)plain->s, rsa_pkey, pad);
313 [ # # ]: 0 : if (ret == -1) {
314 [ # # # # ]: 0 : D("RSA public decrypt failed ret=%d len_cipher_data=%d",ret,ciphered->len);
315 : 0 : zx_report_openssl_error("zx_public_decrypt_rsa fail");
316 : 0 : return 0;
317 : : }
318 [ # # # # ]: 0 : ASSERTOP(ret, <=, siz);
319 : 0 : plain->len = ret;
320 : 0 : plain->s[ret] = 0;
321 : 0 : return plain;
322 : : }
323 : :
324 : : /*() RSA private key decryption. See zxid_read_private_key() and zxid_extract_private_key()
325 : : * for ways to read in the private key data structure.
326 : : * N.B. This function +only+ does the private key part. It does not
327 : : * perform combined dec-session-key-with-priv-key-and-then-data-with-session-key
328 : : * operation, though this function could be used as a component to implement
329 : : * such a system.
330 : : *
331 : : * This is considered a low level function. See zxenc_privkey_dec() for a higher level solution. */
332 : :
333 : : /* Called by: zxenc_privkey_dec x2 */
334 : : struct zx_str* zx_rsa_priv_dec(struct zx_ctx* c, struct zx_str* ciphered, RSA* rsa_pkey, int pad)
335 : 103 : {
336 : : struct zx_str* plain;
337 : 103 : int ret, siz = RSA_size(rsa_pkey);
338 : 103 : plain = zx_new_len_str(c, siz);
339 [ - + ]: 103 : if (!plain)
340 : 0 : return 0;
341 : 103 : ret = RSA_private_decrypt(ciphered->len, (unsigned char*)ciphered->s, (unsigned char*)plain->s, rsa_pkey, pad);
342 [ - + ]: 103 : if (ret == -1) {
343 [ # # # # ]: 0 : D("RSA private decrypt failed ret=%d len_cipher_data=%d",ret,ciphered->len);
344 : 0 : zx_report_openssl_error("zx_priv_decrypt_rsa fail");
345 : 0 : return 0;
346 : : }
347 [ - + # # ]: 103 : ASSERTOP(ret, <=, siz);
348 : 103 : plain->len = ret;
349 : 103 : plain->s[ret] = 0;
350 : 103 : return plain;
351 : : }
352 : :
353 : : /*() RSA private key encryption. See zxid_read_private_key() and zxid_extract_private_key()
354 : : * for ways to read in the private key data structure. */
355 : :
356 : : /* Called by: */
357 : : struct zx_str* zx_rsa_priv_enc(struct zx_ctx* c, struct zx_str* plain, RSA* rsa_pkey, int pad)
358 : 0 : {
359 : : struct zx_str* ciphered;
360 : 0 : int ret, siz = RSA_size(rsa_pkey);
361 : 0 : ciphered = zx_new_len_str(c, siz);
362 [ # # ]: 0 : if (!ciphered)
363 : 0 : return 0;
364 : 0 : ret = RSA_private_encrypt(plain->len, (unsigned char*)plain->s, (unsigned char*)ciphered->s, rsa_pkey, pad);
365 [ # # ]: 0 : if (ret == -1) {
366 [ # # # # ]: 0 : D("RSA private encrypt failed ret=%d len_plain=%d", ret, plain->len);
367 : 0 : zx_report_openssl_error("zx_priv_encrypt_rsa fail");
368 : 0 : return 0;
369 : : }
370 [ # # # # ]: 0 : ASSERTOP(ret, <=, siz);
371 : 0 : ciphered->len = ret;
372 : 0 : ciphered->s[ret] = 0;
373 : 0 : return ciphered;
374 : : }
375 : :
376 : : /*() Obtain RSA public key from X509 certificate. The certificate must have been
377 : : * previously read into a data structure. See zxid_read_cert() and zxid_extract_cert() */
378 : :
379 : : /* Called by: zxenc_pubkey_enc, zxlog_write_line */
380 : : RSA* zx_get_rsa_pub_from_cert(X509* cert, char* logkey)
381 : 960 : {
382 : : EVP_PKEY* evp_pkey;
383 : : struct rsa_st* rsa_pkey;
384 : 960 : evp_pkey = X509_get_pubkey(cert);
385 [ - + ]: 960 : if (!evp_pkey) {
386 : 0 : ERR("RSA enc: failed to get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %s", logkey);
387 : 0 : zx_report_openssl_error("zx_get_rsa_pub_from_cert");
388 : 0 : return 0;
389 : : }
390 : 960 : rsa_pkey = EVP_PKEY_get1_RSA(evp_pkey);
391 [ - + ]: 960 : if (!rsa_pkey) {
392 : 0 : ERR("RSA enc: failed to extract RSA get public key from certificate (perhaps you have not supplied any certificate, or it is corrupt or of wrong type) %s", logkey);
393 : 0 : zx_report_openssl_error("zx_get_rsa_pub_from_cert");
394 : 0 : return 0;
395 : : }
396 : 960 : return rsa_pkey;
397 : : }
398 : :
399 : : /*() ZXID centralized hook for obtaning randin numbers. This backends to
400 : : * OpenSSL random number gnerator and seeds from /dev/urandom where
401 : : * available. If you want to use /dev/random, which may block, you need
402 : : * to recompile with ZXID_TRUE_RAND set to true. */
403 : :
404 : : /* Called by: main x2, zx_get_symkey, zxenc_pubkey_enc, zxid_mk_at_cert, zxid_mk_id, zxid_mk_id_attr, zxid_mk_self_sig_cert, zxlog_alloc_zbuf, zxlog_write_line */
405 : : void zx_rand(char* buf, int n_bytes)
406 : 2803 : {
407 : : #ifdef USE_OPENSSL
408 : : #if ZXID_TRUE_RAND
409 : : RAND_bytes(buf, n_bytes);
410 : : #else
411 : 2803 : RAND_pseudo_bytes((unsigned char*)buf, n_bytes);
412 : : #endif
413 : : #else
414 : : ERR("ZXID was compiled without USE_OPENSSL. This means random number generation facilities are unavailable. Recompile ZXID or acknowledge that there is no security. n_rand_bytes=%d", n);
415 : : #endif
416 : 2803 : }
417 : :
418 : : /* Called by: zxid_mk_at_cert x10, zxid_mk_self_sig_cert x6 */
419 : : static void zxid_add_name_field(X509_NAME* subj, int typ, int nid, char* val)
420 : 3693 : {
421 : : X509_NAME_ENTRY* ne;
422 [ + - - + ]: 3693 : if (!val || !*val)
423 : 0 : return;
424 : 3693 : ne = X509_NAME_ENTRY_create_by_NID(0, nid, typ, (unsigned char*)val, strlen(val));
425 : 3693 : X509_NAME_add_entry(subj, ne, X509_NAME_entry_count(subj), 0);
426 : : }
427 : :
428 : : /*() Create Self-Signed Certificate-Private Key pair and Certificate Signing Request
429 : : * This function is invoked when AUTO_CERT is set and a certificate is missing.
430 : : * As this is not expected to be frequent, we are cavalier about releasing
431 : : * the memory needed for each intermediate step.
432 : : *
433 : : * cf:: zxid configuration object, of which cf->ctx will be used for memory allocation
434 : : * buflen:: sizeof(buf)
435 : : * buf:: Buffer used for rendering pem representations of the certificate
436 : : * log key:: Who and why is calling
437 : : * name:: Name of the certificate file to be created
438 : : * returns:: 0 on failure, 1 on success
439 : : *
440 : : * See also: keygen() in keygen.c */
441 : :
442 : : /* Called by: zxid_read_cert, zxid_read_private_key */
443 : : int zxid_mk_self_sig_cert(zxid_conf* cf, int buflen, char* buf, const char* lk, const char* name)
444 : 2 : {
445 : : #ifdef USE_OPENSSL
446 : : BIO* wbio_cert;
447 : : BIO* wbio_pkey;
448 : : BIO* wbio_csr;
449 : : int len, lenq, um;
450 : : long cert_ser;
451 : : char* p;
452 : : char* q;
453 : : time_t ts;
454 : : X509* x509ss;
455 : : X509_REQ* req;
456 : : X509_REQ_INFO* ri;
457 : : EVP_PKEY* pkey;
458 : : EVP_PKEY* tmp_pkey;
459 : : RSA* rsa;
460 : : X509_EXTENSION* ext;
461 : : char cn[256];
462 : : char ou[256];
463 : :
464 : 2 : X509V3_add_standard_extensions();
465 : :
466 [ - + # # ]: 2 : D("keygen start lk(%s) name(%s)", lk, name);
467 : :
468 : 2 : p = strstr(cf->url, "://");
469 [ + - ]: 2 : if (p) {
470 : 2 : p += sizeof("://")-1;
471 : 2 : len = strcspn(p, ":/");
472 [ - + ]: 2 : if (len > sizeof(cn)-2)
473 : 0 : len = sizeof(cn)-2;
474 : 2 : memcpy(cn, p, len);
475 : 2 : cn[len] = 0;
476 : : } else {
477 : 0 : strcpy(cn, "Unknown server cn. Misconfiguration.");
478 : : }
479 : :
480 : 2 : snprintf(ou, sizeof(ou)-1, "SSO Dept ZXID Auto-Cert %s", cf->url);
481 : 2 : ou[sizeof(ou)-1] = 0; /* must terminate manually as on win32 termination is not guaranteed */
482 : :
483 : 2 : ts = time(0);
484 : 2 : RAND_seed(&ts,sizeof(ts));
485 : : #ifdef WINDOWS
486 : : RAND_screen(); /* Loading video display memory into random state */
487 : : #endif
488 : :
489 : : /* Here's the beef: Generate keypair */
490 : :
491 : 2 : pkey=EVP_PKEY_new();
492 : : DD("keygen preparing rsa key %s", lk);
493 : 2 : rsa = RSA_generate_key(1024 /*bits*/, 0x10001 /*65537*/, 0 /*req_cb*/, 0 /*arg*/);
494 : : DD("keygen rsa key generated %s", name);
495 : 2 : EVP_PKEY_assign_RSA(pkey, rsa);
496 : :
497 : : #if 0
498 : : /* Key generation is a big operation. Write in the new random state. */
499 : : t = time(0);
500 : : RAND_seed(&t,sizeof(t));
501 : : RAND_write_file(randomfile);
502 : : #endif
503 : :
504 : : /* Now handle the public key part, i.e. create self signed and
505 : : * certificate request. This starts by making a request that
506 : : * contains all relevant fields. */
507 : :
508 : 2 : req=X509_REQ_new();
509 : 2 : ri=req->req_info;
510 : :
511 : : DD("keygen populate: set version %d (real vers is one higher)", 2);
512 : 2 : ASN1_INTEGER_set(ri->version, 2L /* version 3 (binary value is one less) */);
513 : :
514 : : #if 0 /* See cn code above */
515 : : /* Parse domain name out of the URL: skip https:// and then scan name without port or path */
516 : :
517 : : for (p = cf->url; !ONE_OF_2(*p, '/', 0); ++p) ;
518 : : if (*p != '/') goto badurl;
519 : : ++p;
520 : : if (*p != '/') {
521 : : badurl:
522 : : ERR("Malformed URL: does not start by https:// or http:// -- URL(%s)", cf->url);
523 : : return 0;
524 : : }
525 : : ++p;
526 : : for (q = cn; !ONE_OF_3(*p, ':', '/', 0) && q < cn + sizeof(cn)-1; ++q, ++p) *q = *p;
527 : : *q = 0;
528 : :
529 : : D("keygen populate DN: cn(%s) org(%s) c(%s) url=%p cn=%p p=%p q=%p", cn, cf->org_name, cf->country, cf->url, cn, p, q);
530 : : #endif
531 : :
532 : : /* Note on string types and allowable char sets:
533 : : * V_ASN1_PRINTABLESTRING [A-Za-z0-9 '()+,-./:=?] -- Any domain name, but not query string
534 : : * V_ASN1_IA5STRING Any 7bit string
535 : : * V_ASN1_T61STRING 8bit string */
536 : :
537 : : /* Construct DN part by part. We want cn=www.site.com,o=ZXID Auto-Cert */
538 : :
539 : 2 : zxid_add_name_field(ri->subject, V_ASN1_PRINTABLESTRING, NID_commonName, cn);
540 : 2 : zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_organizationalUnitName, ou);
541 : 2 : zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_organizationName, cf->org_name);
542 : :
543 : 2 : zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_localityName, cf->locality);
544 : 2 : zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_stateOrProvinceName, cf->state);
545 : 2 : zxid_add_name_field(ri->subject, V_ASN1_T61STRING, NID_countryName, cf->country);
546 : :
547 : : #if 0
548 : : X509_ATTRIBUTE* xa;
549 : : ASN1_BIT_STRING* bs;
550 : : ASN1_TYPE* at;
551 : :
552 : : /* It seems this gives indigestion to the default CA */
553 : : DD("keygen populate attributes %s", lk); /* Add attributes: we really only need cn */
554 : :
555 : : xa = X509_ATTRIBUTE_new();
556 : : xa->value.set = sk_ASN1_TYPE_new_null();
557 : : /*xa->single = 1; **** this may also be set on some versions */
558 : : xa->object=OBJ_nid2obj(NID_commonName);
559 : :
560 : : bs = ASN1_BIT_STRING_new();
561 : : bs->type = V_ASN1_PRINTABLESTRING;
562 : : ASN1_STRING_set(bs, cn, strlen(cn)+1); /* *** +1 why? Some archaic bug work-around? */
563 : :
564 : : at = ASN1_TYPE_new();
565 : : ASN1_TYPE_set(at, bs->type, (char*)bs);
566 : : sk_ASN1_TYPE_push(xa->value.set, at);
567 : : sk_X509_ATTRIBUTE_push(ri->attributes, xa);
568 : : #endif
569 : :
570 : : DD("keygen request populated %s", lk);
571 : 2 : X509_REQ_set_pubkey(req, pkey);
572 : : /*req->req_info->req_kludge=0; / * no asn1 kludge *** filed deleted as of 0.9.7b?!? */
573 : :
574 : : DD("keygen signing request %s", lk);
575 : 2 : X509_REQ_sign(req, pkey, EVP_md5());
576 : :
577 : : /* ----- X509 create self signed certificate ----- */
578 : :
579 : : DD("keygen making x509ss %s", lk);
580 : 2 : x509ss = X509_new();
581 : 2 : X509_set_version(x509ss, 2); /* Set version to V3 and serial number to zero */
582 : 2 : zx_rand((char*)&cert_ser, 4);
583 : 2 : ASN1_INTEGER_set(X509_get_serialNumber(x509ss), cert_ser);
584 : : DD("keygen setting various x509ss fields %s", lk);
585 : :
586 : 2 : X509_set_issuer_name(x509ss, X509_REQ_get_subject_name(req));
587 : : #if 1
588 : 2 : ASN1_TIME_set(X509_get_notBefore(x509ss),0);
589 : 2 : ASN1_TIME_set(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
590 : : #else
591 : : X509_gmtime_adj(X509_get_notBefore(x509ss),0);
592 : : X509_gmtime_adj(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
593 : : #endif
594 : 2 : X509_set_subject_name(x509ss, X509_REQ_get_subject_name(req));
595 : :
596 : : DD("keygen setting x509ss pubkey %s", lk);
597 : 2 : tmp_pkey =X509_REQ_get_pubkey(req);
598 : 2 : X509_set_pubkey(x509ss, tmp_pkey);
599 : 2 : EVP_PKEY_free(tmp_pkey);
600 : :
601 : : /* Set up V3 context struct and add certificate extensions. Note
602 : : * that we need to add (full) suite of CA extensions, otherwise
603 : : * our cert is not valid for signing itself. */
604 : :
605 : 2 : ext = X509V3_EXT_conf_nid(0, 0, NID_basic_constraints, "CA:TRUE,pathlen:3");
606 : 2 : X509_add_ext(x509ss, ext, -1);
607 : :
608 : 2 : ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_cert_type, "client,server,email,objsign,sslCA,emailCA,objCA");
609 : 2 : X509_add_ext(x509ss, ext, -1);
610 : :
611 : 2 : ext = X509V3_EXT_conf_nid(0, 0, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign");
612 : 2 : X509_add_ext(x509ss, ext, -1);
613 : :
614 : 2 : ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_comment, "Auto-Cert, see zxid.org");
615 : 2 : X509_add_ext(x509ss, ext, -1);
616 : :
617 : : DD("keygen signing x509ss %s", lk);
618 [ - + ]: 2 : if (!(X509_sign(x509ss, pkey, EVP_md5()))) {
619 : 0 : ERR("Failed to sign x509ss %s", lk);
620 : 0 : zx_report_openssl_error("X509_sign");
621 : 0 : return 0;
622 : : }
623 : : DD("keygen x509ss ready %s", lk);
624 : :
625 : : /* ----- Output phase ----- */
626 : :
627 : 2 : um = umask(0077); /* Key material should be readable only by owner */
628 : :
629 : 2 : wbio_csr = BIO_new(BIO_s_mem());
630 : : DD("write_csr %s", lk);
631 [ - + ]: 2 : if (!PEM_write_bio_X509_REQ(wbio_csr, req)) {
632 : 0 : ERR("write_csr %s", lk);
633 : 0 : zx_report_openssl_error("write_csr");
634 : 0 : return 0;
635 : : }
636 : 2 : len = BIO_get_mem_data(wbio_csr, &p);
637 : :
638 : 2 : write_all_path_fmt("auto_cert csr", buflen, buf,
639 : : "%s" ZXID_PEM_DIR "csr-%s", cf->path, name,
640 : : "%.*s", len, p);
641 : 2 : BIO_free_all(wbio_csr);
642 : :
643 : : /* Output combined self signed plus private key file. It is important
644 : : * that this happens after csr so that buf is left with this data
645 : : * so that the caller can then parse it. */
646 : :
647 : 2 : wbio_cert = BIO_new(BIO_s_mem());
648 : : DD("write_cert %s", lk);
649 [ - + ]: 2 : if (!PEM_write_bio_X509(wbio_cert, x509ss)) {
650 : 0 : ERR("write_cert %s", lk);
651 : 0 : zx_report_openssl_error("write_cert");
652 : 0 : return 0;
653 : : }
654 : 2 : len = BIO_get_mem_data(wbio_cert, &p);
655 : :
656 : 2 : wbio_pkey = BIO_new(BIO_s_mem());
657 : : DD("write_private_key %s", lk);
658 [ - + ]: 2 : if (!PEM_write_bio_PrivateKey(wbio_pkey, pkey, 0,0,0,0,0)) {
659 : 0 : ERR("write_private_key %s", lk);
660 : 0 : zx_report_openssl_error("write_private_key");
661 : 0 : return 0;
662 : : }
663 : 2 : lenq = BIO_get_mem_data(wbio_pkey, &q);
664 : :
665 : 2 : write_all_path_fmt("auto_cert ss", buflen, buf,
666 : : "%s" ZXID_PEM_DIR "%s", cf->path, name,
667 : : "%.*s%.*s", len, p, lenq, q);
668 : :
669 : 2 : BIO_free_all(wbio_cert);
670 : 2 : BIO_free_all(wbio_pkey);
671 : :
672 : 2 : umask(um);
673 : :
674 : 2 : EVP_PKEY_free(pkey);
675 : 2 : X509_REQ_free(req);
676 : 2 : X509_free(x509ss);
677 : 2 : X509V3_EXT_cleanup();
678 : 2 : OBJ_cleanup();
679 : :
680 : 2 : zxlog(cf, 0, 0, 0, 0, 0, 0, 0, 0, "K", "KEYGEN", name, 0);
681 [ - + # # ]: 2 : D("keygen done. %s", lk);
682 : 2 : return 1;
683 : : #else
684 : : ERR("ZXID was compiled without USE_OPENSSL. This means self signed certificate generation facility is unavailable. Recompile ZXID. %s", lk);
685 : : return 0;
686 : : #endif
687 : : }
688 : :
689 : : /*
690 : :
691 : : A Practical Approach of X.509 Attribute Certificate Framework as Support to Obtain Privilege Delegation
692 : : Jose A. Montenegro and Fernando Moya
693 : : Computer Science Department, E.T.S. Ingenieria Informatica, Universidad de Malage, Spain
694 : : Lecture Notes in Computer Science, 2004, Volume 3093/2004, 624, DOI: 10.1007/978-3-540-25980-0_13
695 : :
696 : : Abstract This work introduces a particular implementation of the
697 : : X.509 Attribute Certificate framework (Xac), presented in the ITU-T
698 : : Recommendation. The implementation is based on the use of the Openssl
699 : : library, that we have chosen for its advantages in comparison with
700 : : other libraries. The paper also describes how the implementation is
701 : : middleware-oriented, focusing on the delegation model specified by
702 : : ITU-T proposal, and taking into consideration the ETSI report about
703 : : Xac.
704 : :
705 : : RFC3281
706 : : http://tools.ietf.org/html/draft-ietf-pkix-3281update-05
707 : :
708 : : */
709 : :
710 : : /*() Create X509 attribute certificate for one attribute and user specified by nameid (pseudonym)
711 : : *
712 : : * cf:: zxid configuration object, of which cf->ctx will be used for memory allocation
713 : : * buflen:: sizeof(buf)
714 : : * buf:: Buffer used for rendering pem representation of the certificate
715 : : * log key:: Who and why is calling
716 : : * nameid:: Name of the subject
717 : : * name:: Name of the attribute in certificate
718 : : * val:: Value of the attribute in certificate
719 : : * returns:: 0 on failure, 1 on success
720 : : */
721 : :
722 : : /* Called by: x509_test, zxid_map_val_ss */
723 : : int zxid_mk_at_cert(zxid_conf* cf, int buflen, char* buf, const char* lk, zxid_nid* nameid, const char* name, struct zx_str* val)
724 : 409 : {
725 : : #ifdef USE_OPENSSL
726 : : BIO* wbio_cert;
727 : : int len;
728 : : long cert_ser;
729 : : char* p;
730 : : time_t ts;
731 : : X509* x509ss;
732 : : X509_NAME* issuer;
733 : : X509_NAME* subject;
734 : : X509_EXTENSION* ext;
735 : : X509* sign_cert;
736 : : EVP_PKEY* sign_pkey;
737 : : char cn[256];
738 : : char ou[256];
739 : :
740 : 409 : X509V3_add_standard_extensions();
741 : :
742 [ + + - + ]: 409 : D("keygen start lk(%s) name(%s)", lk, name);
743 : :
744 : 409 : p = strstr(cf->url, "://");
745 [ + - ]: 409 : if (p) {
746 : 409 : p += sizeof("://")-1;
747 : 409 : len = strcspn(p, ":/");
748 [ - + ]: 409 : if (len > sizeof(cn)-2)
749 : 0 : len = sizeof(cn)-2;
750 : 409 : memcpy(cn, p, len);
751 : 409 : cn[len] = 0;
752 : : } else {
753 : 0 : strcpy(cn, "Unknown server cn. Misconfiguration.");
754 : : }
755 : :
756 : 409 : snprintf(ou, sizeof(ou)-1, "SSO Dept ZXID Auto-Cert %s", cf->url);
757 : 409 : ou[sizeof(ou)-1] = 0; /* must terminate manually as on win32 termination is not guaranteed */
758 : :
759 : 409 : ts = time(0);
760 : 409 : RAND_seed(&ts,sizeof(ts));
761 : : #ifdef WINDOWS
762 : : RAND_screen(); /* Loading video display memory into random state */
763 : : #endif
764 : :
765 : : //ASN1_INTEGER_set(ri->version, 2L /* version 3 (binary value is one less) */);
766 : :
767 : : /* Note on string types and allowable char sets:
768 : : * V_ASN1_PRINTABLESTRING [A-Za-z0-9 '()+,-./:=?] -- Any domain name, but not query string
769 : : * V_ASN1_IA5STRING Any 7bit string
770 : : * V_ASN1_T61STRING 8bit string */
771 : :
772 : 409 : issuer = X509_NAME_new();
773 : 409 : subject = X509_NAME_new();
774 : :
775 : : /* Construct DN part by part. We want cn=www.site.com,o=ZXID Auto-Cert */
776 : :
777 : 409 : zxid_add_name_field(issuer, V_ASN1_PRINTABLESTRING, NID_commonName, cn);
778 : 409 : zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_organizationalUnitName, ou);
779 : 409 : zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_organizationName, cf->org_name);
780 : :
781 : 409 : zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_localityName, cf->locality);
782 : 409 : zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_stateOrProvinceName, cf->state);
783 : 409 : zxid_add_name_field(issuer, V_ASN1_T61STRING, NID_countryName, cf->country);
784 : :
785 : : /* Construct Subject part by part. */
786 : :
787 [ + - ]: 409 : if (nameid) {
788 [ + - + - : 409 : zxid_add_name_field(subject, V_ASN1_PRINTABLESTRING, NID_commonName,
+ - ]
789 : : zx_str_to_c(cf->ctx, ZX_GET_CONTENT(nameid)));
790 : 409 : zxid_add_name_field(subject, V_ASN1_T61STRING, NID_organizationalUnitName,
791 : : zx_str_to_c(cf->ctx, &nameid->SPNameQualifier->g)); /* SP */
792 : 409 : zxid_add_name_field(subject, V_ASN1_T61STRING, NID_organizationName,
793 : : zx_str_to_c(cf->ctx, &nameid->NameQualifier->g)); /* IdP */
794 : : } else {
795 : 0 : zxid_add_name_field(subject, V_ASN1_PRINTABLESTRING, NID_commonName, "unspecified-see-zxid_mk_at_cert");
796 : : }
797 : :
798 : : /* ----- Create X509 certificate ----- */
799 : :
800 : 409 : x509ss = X509_new();
801 : 409 : X509_set_version(x509ss, 2); /* Set version to V3 and serial number to zero */
802 : 409 : zx_rand((char*)&cert_ser, 4);
803 : 409 : ASN1_INTEGER_set(X509_get_serialNumber(x509ss), cert_ser);
804 : :
805 : 409 : X509_set_issuer_name(x509ss, issuer);
806 : : #if 1
807 : 409 : ASN1_TIME_set(X509_get_notBefore(x509ss),0);
808 : 409 : ASN1_TIME_set(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
809 : : #else
810 : : X509_gmtime_adj(X509_get_notBefore(x509ss),0);
811 : : X509_gmtime_adj(X509_get_notAfter(x509ss), 0x7fffffffL); /* The end of the 32 bit Unix epoch */
812 : : #endif
813 : 409 : X509_set_subject_name(x509ss, subject);
814 : :
815 : : #if 0 /* *** schedule to remove */
816 : : /* Set up V3 context struct and add certificate extensions. */
817 : :
818 : : ext = X509V3_EXT_conf_nid(0, 0, NID_basic_constraints, "CA:TRUE,pathlen:3");
819 : : X509_add_ext(x509ss, ext, -1);
820 : :
821 : : ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_cert_type, "client,server,email,objsign,sslCA,emailCA,objCA");
822 : : X509_add_ext(x509ss, ext, -1);
823 : :
824 : : ext = X509V3_EXT_conf_nid(0, 0, NID_key_usage, "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyAgreement,keyCertSign,cRLSign");
825 : : X509_add_ext(x509ss, ext, -1);
826 : : #endif
827 : :
828 : 409 : ext = X509V3_EXT_conf_nid(0, 0, NID_netscape_comment, "Attribute cert, see zxid.org");
829 : 409 : X509_add_ext(x509ss, ext, -1);
830 : :
831 : : #if 0
832 : : X509_ATTRIBUTE* xa;
833 : : ASN1_BIT_STRING* bs;
834 : : ASN1_TYPE* at;
835 : :
836 : : /* It seems this gives indigestion to the default CA */
837 : : DD("keygen populate attributes %s", lk); /* Add attributes: we really only need cn */
838 : :
839 : : xa = X509_ATTRIBUTE_new();
840 : : xa->value.set = sk_ASN1_TYPE_new_null();
841 : : /*xa->single = 1; **** this may also be set on some versions */
842 : : xa->object=OBJ_nid2obj(NID_commonName);
843 : :
844 : : bs = ASN1_BIT_STRING_new();
845 : : bs->type = V_ASN1_PRINTABLESTRING;
846 : : ASN1_STRING_set(bs, cn, strlen(cn)+1); /* *** +1 why? Some archaic bug work-around? */
847 : :
848 : : at = ASN1_TYPE_new();
849 : : ASN1_TYPE_set(at, bs->type, (char*)bs);
850 : : sk_ASN1_TYPE_push(xa->value.set, at);
851 : : sk_X509_ATTRIBUTE_push(ri->attributes, xa);
852 : : STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, X509_ATTRIBUTE *attr);
853 : :
854 : : /* *** Exactly where on x509ss are the attributes supposed to attach?!? */
855 : : #endif
856 : :
857 : 409 : zxid_lazy_load_sign_cert_and_pkey(cf, &sign_cert, &sign_pkey, "mk_at_cert");
858 : :
859 : : DD("keygen signing x509ss %s", lk);
860 [ - + ]: 409 : if (!(X509_sign(x509ss, sign_pkey, EVP_md5()))) {
861 : 0 : ERR("Failed to sign x509ss %s", lk);
862 : 0 : zx_report_openssl_error("X509_sign");
863 : 0 : return 0;
864 : : }
865 : : DD("keygen x509ss ready %s", lk);
866 : :
867 : : /* ----- Output phase ----- */
868 : :
869 : 409 : wbio_cert = BIO_new(BIO_s_mem());
870 : : DD("write_cert %s", lk);
871 [ - + ]: 409 : if (!PEM_write_bio_X509(wbio_cert, x509ss)) {
872 : 0 : ERR("write_cert %s", lk);
873 : 0 : zx_report_openssl_error("write_cert");
874 : 0 : return 0;
875 : : }
876 : 409 : len = BIO_get_mem_data(wbio_cert, &p);
877 : 409 : memcpy(buf, p, MIN(len, buflen-1));
878 : 409 : buf[MIN(len, buflen-1)] = 0;
879 : :
880 : : //***write_all_path_fmt("auto_cert ss", buflen, buf, "%s" ZXID_PEM_DIR "%s", cf->path, name, "%.*s", len, p);
881 : :
882 : 409 : BIO_free_all(wbio_cert);
883 : :
884 : 409 : X509_free(x509ss);
885 : 409 : X509V3_EXT_cleanup();
886 : 409 : OBJ_cleanup();
887 : :
888 : 409 : zxlog(cf, 0, 0, 0, 0, 0, 0, 0, 0, "K", "X509ATCERT", name, 0);
889 [ + + - + ]: 409 : D("at cert done. %s", lk);
890 : 409 : return 1;
891 : : #else
892 : : ERR("ZXID was compiled without USE_OPENSSL. This means X509 attribute certificate generation facility is unavailable. Recompile ZXID. %s", lk);
893 : : return 0;
894 : : #endif
895 : : }
896 : :
897 : : /* Adapted by Sampo from FreeBSD md5_crypt.c, which is licensed as follows
898 : : * ----------------------------------------------------------------------------
899 : : * "THE BEER-WARE LICENSE" (Revision 42):
900 : : * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
901 : : * can do whatever you want with this stuff. If we meet some day, and you think
902 : : * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
903 : : * ----------------------------------------------------------------------------
904 : : */
905 : :
906 : : extern char pw_basis_64[64];
907 : :
908 : : /* Called by: zx_md5_crypt x6 */
909 : 66 : static void to64(char *s, unsigned long v, int n) {
910 [ + + ]: 374 : while (--n >= 0) {
911 : 242 : *s++ = pw_basis_64[v & 0x3f];
912 : 242 : v >>= 6;
913 : : }
914 : 66 : }
915 : :
916 : : /*() Compute MD5-Crypt password hash (starts by $1$)
917 : : *
918 : : * pw:: Password in plain
919 : : * salt:: 0-8 chars of salt. Preceding $1$ is automatically skipped. Salt ends in $ or nul.
920 : : * buf:: must be at least 120 chars
921 : : * return:: buf, nul terminated */
922 : :
923 : : /* Called by: main x2, zxid_pw_authn */
924 : : char* zx_md5_crypt(const char* pw, const char* salt, char* buf)
925 : 11 : {
926 : 11 : const char* magic = "$1$"; /* magic prefix to identify algo */
927 : : char* p;
928 : : const char *sp, *ep;
929 : : unsigned char final[16];
930 : : int sl, pl, i, j;
931 : : MD5_CTX ctx, ctx1;
932 : : unsigned long l;
933 : :
934 : : /* Refine the Salt first */
935 : 11 : sp = salt;
936 : :
937 : : /* If it starts with the magic string, then skip that */
938 [ + - ]: 11 : if (!strncmp(sp, magic, strlen(magic)))
939 : 11 : sp += strlen(magic);
940 : :
941 : : /* It stops at the first '$', max 8 chars */
942 [ + - + + : 11 : for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) ;
+ - ]
943 : 11 : sl = ep - sp; /* get the length of the true salt */
944 : :
945 : 11 : MD5_Init(&ctx);
946 : 11 : MD5_Update(&ctx, (unsigned const char *)pw, strlen(pw)); /* pw 1st, as it's most unknown */
947 : 11 : MD5_Update(&ctx, (unsigned const char *)magic, strlen(magic)); /* Then our magic string */
948 : 11 : MD5_Update(&ctx, (unsigned const char *)sp, sl); /* Then the raw salt */
949 : :
950 : : /* Then just as many characters of the MD5(pw,salt,pw) */
951 : 11 : MD5_Init(&ctx1);
952 : 11 : MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
953 : 11 : MD5_Update(&ctx1, (unsigned const char *)sp, sl);
954 : 11 : MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
955 : 11 : MD5_Final(final, &ctx1);
956 [ + + ]: 22 : for (pl = strlen(pw); pl > 0; pl -= 16)
957 : 11 : MD5_Update(&ctx, (unsigned const char *)final, pl>16 ? 16 : pl);
958 : :
959 : 11 : ZERO(final, sizeof(final)); /* Don't leave anything around in vm they could use. */
960 : :
961 : : /* Then something really weird... */
962 [ + + ]: 44 : for (j = 0, i = strlen(pw); i; i >>= 1)
963 [ + + ]: 33 : if (i & 1)
964 : 22 : MD5_Update(&ctx, (unsigned const char *)final+j, 1);
965 : : else
966 : 11 : MD5_Update(&ctx, (unsigned const char *)pw+j, 1);
967 : :
968 : 11 : strcpy(buf, magic); /* Start the output string */
969 : 11 : strncat(buf, sp, sl);
970 : 11 : strcat(buf, "$");
971 : :
972 : 11 : MD5_Final(final, &ctx);
973 : :
974 : : /* and now, just to make sure things don't run too fast
975 : : * On a 60 Mhz Pentium this takes 34 msec, so you would
976 : : * need 30 seconds to build a 1000 entry dictionary... */
977 [ + + ]: 11011 : for (i = 0; i < 1000; i++) {
978 : 11000 : MD5_Init(&ctx1);
979 [ + + ]: 11000 : if (i & 1)
980 : 5500 : MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
981 : : else
982 : 5500 : MD5_Update(&ctx1, (unsigned const char *)final, 16);
983 : :
984 [ + + ]: 11000 : if (i % 3)
985 : 7326 : MD5_Update(&ctx1, (unsigned const char *)sp, sl);
986 : :
987 [ + + ]: 11000 : if (i % 7)
988 : 9427 : MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
989 : :
990 [ + + ]: 11000 : if (i & 1)
991 : 5500 : MD5_Update(&ctx1, (unsigned const char *)final, 16);
992 : : else
993 : 5500 : MD5_Update(&ctx1, (unsigned const char *)pw, strlen(pw));
994 : 11000 : MD5_Final(final, &ctx1);
995 : : }
996 : :
997 : 11 : p = buf + strlen(buf);
998 : :
999 : 11 : l = (final[0] << 16) | (final[6] << 8) | final[12]; to64(p, l, 4); p += 4;
1000 : 11 : l = (final[1] << 16) | (final[7] << 8) | final[13]; to64(p, l, 4); p += 4;
1001 : 11 : l = (final[2] << 16) | (final[8] << 8) | final[14]; to64(p, l, 4); p += 4;
1002 : 11 : l = (final[3] << 16) | (final[9] << 8) | final[15]; to64(p, l, 4); p += 4;
1003 : 11 : l = (final[4] << 16) | (final[10] << 8) | final[5]; to64(p, l, 4); p += 4;
1004 : 11 : l = final[11]; to64(p, l, 2); p += 2;
1005 : 11 : *p = '\0';
1006 : :
1007 : 11 : ZERO(final, sizeof(final)); /* Don't leave anything around in vm they could use. */
1008 : 11 : return buf;
1009 : : }
1010 : :
1011 : : /* EOF - zxcrypto.c */
|