/src/samba/third_party/heimdal/lib/hcrypto/pkcs12.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2006 Kungliga Tekniska Högskolan |
3 | | * (Royal Institute of Technology, Stockholm, Sweden). |
4 | | * All rights reserved. |
5 | | * |
6 | | * Redistribution and use in source and binary forms, with or without |
7 | | * modification, are permitted provided that the following conditions |
8 | | * are met: |
9 | | * |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * |
13 | | * 2. Redistributions in binary form must reproduce the above copyright |
14 | | * notice, this list of conditions and the following disclaimer in the |
15 | | * documentation and/or other materials provided with the distribution. |
16 | | * |
17 | | * 3. Neither the name of the Institute nor the names of its contributors |
18 | | * may be used to endorse or promote products derived from this software |
19 | | * without specific prior written permission. |
20 | | * |
21 | | * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND |
22 | | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE |
25 | | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
27 | | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
28 | | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
29 | | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
30 | | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
31 | | * SUCH DAMAGE. |
32 | | */ |
33 | | |
34 | | #include <config.h> |
35 | | #include <roken.h> |
36 | | #include <assert.h> |
37 | | |
38 | | #include <pkcs12.h> |
39 | | #include <bn.h> |
40 | | |
41 | | int |
42 | | PKCS12_key_gen(const void *key, size_t keylen, |
43 | | const void *salt, size_t saltlen, |
44 | | int id, int iteration, size_t outkeysize, |
45 | | void *out, const EVP_MD *md) |
46 | 0 | { |
47 | 0 | unsigned char *v, *I, hash[EVP_MAX_MD_SIZE]; |
48 | 0 | unsigned int size, size_I = 0; |
49 | 0 | unsigned char idc = id; |
50 | 0 | EVP_MD_CTX *ctx; |
51 | 0 | unsigned char *outp = out; |
52 | 0 | int i, vlen; |
53 | | |
54 | | /** |
55 | | * The argument key is pointing to an utf16 string, and thus |
56 | | * keylen that is no a multiple of 2 is invalid. |
57 | | */ |
58 | 0 | if (keylen & 1) |
59 | 0 | return 0; |
60 | | |
61 | 0 | ctx = EVP_MD_CTX_create(); |
62 | 0 | if (ctx == NULL) |
63 | 0 | return 0; |
64 | | |
65 | 0 | vlen = EVP_MD_block_size(md); |
66 | 0 | v = malloc(vlen + 1); |
67 | 0 | if (v == NULL) { |
68 | 0 | EVP_MD_CTX_destroy(ctx); |
69 | 0 | return 0; |
70 | 0 | } |
71 | | |
72 | 0 | I = calloc(1, vlen * 2); |
73 | 0 | if (I == NULL) { |
74 | 0 | EVP_MD_CTX_destroy(ctx); |
75 | 0 | free(v); |
76 | 0 | return 0; |
77 | 0 | } |
78 | | |
79 | 0 | if (salt && saltlen > 0) { |
80 | 0 | for (i = 0; i < vlen; i++) |
81 | 0 | I[i] = ((const unsigned char*)salt)[i % saltlen]; |
82 | 0 | size_I += vlen; |
83 | 0 | } |
84 | | /* |
85 | | * There is a diffrence between the no password string and the |
86 | | * empty string, in the empty string the UTF16 NUL terminator is |
87 | | * included into the string. |
88 | | */ |
89 | 0 | if (key) { |
90 | 0 | for (i = 0; i < vlen / 2; i++) { |
91 | 0 | I[(i * 2) + size_I] = 0; |
92 | 0 | I[(i * 2) + size_I + 1] = ((const unsigned char*)key)[i % (keylen + 1)]; |
93 | 0 | } |
94 | 0 | size_I += vlen; |
95 | 0 | } |
96 | |
|
97 | 0 | while (1) { |
98 | 0 | BIGNUM *bnB, *bnOne; |
99 | |
|
100 | 0 | if (!EVP_DigestInit_ex(ctx, md, NULL)) { |
101 | 0 | EVP_MD_CTX_destroy(ctx); |
102 | 0 | free(I); |
103 | 0 | free(v); |
104 | 0 | return 0; |
105 | 0 | } |
106 | 0 | for (i = 0; i < vlen; i++) |
107 | 0 | EVP_DigestUpdate(ctx, &idc, 1); |
108 | 0 | EVP_DigestUpdate(ctx, I, size_I); |
109 | 0 | EVP_DigestFinal_ex(ctx, hash, &size); |
110 | |
|
111 | 0 | for (i = 1; i < iteration; i++) |
112 | 0 | EVP_Digest(hash, size, hash, &size, md, NULL); |
113 | |
|
114 | 0 | memcpy(outp, hash, min(outkeysize, size)); |
115 | 0 | if (outkeysize < size) |
116 | 0 | break; |
117 | 0 | outkeysize -= size; |
118 | 0 | outp += size; |
119 | |
|
120 | 0 | for (i = 0; i < vlen; i++) |
121 | 0 | v[i] = hash[i % size]; |
122 | |
|
123 | 0 | bnB = BN_bin2bn(v, vlen, NULL); |
124 | 0 | bnOne = BN_new(); |
125 | 0 | BN_set_word(bnOne, 1); |
126 | |
|
127 | 0 | BN_uadd(bnB, bnB, bnOne); |
128 | |
|
129 | 0 | for (i = 0; i < vlen * 2; i += vlen) { |
130 | 0 | BIGNUM *bnI; |
131 | 0 | int j; |
132 | |
|
133 | 0 | bnI = BN_bin2bn(I + i, vlen, NULL); |
134 | |
|
135 | 0 | BN_uadd(bnI, bnI, bnB); |
136 | |
|
137 | 0 | j = BN_num_bytes(bnI); |
138 | 0 | if (j > vlen) { |
139 | 0 | assert(j == vlen + 1); |
140 | 0 | BN_bn2bin(bnI, v); |
141 | 0 | memcpy(I + i, v + 1, vlen); |
142 | 0 | } else { |
143 | 0 | memset(I + i, 0, vlen - j); |
144 | 0 | BN_bn2bin(bnI, I + i + vlen - j); |
145 | 0 | } |
146 | 0 | BN_free(bnI); |
147 | 0 | } |
148 | 0 | BN_free(bnB); |
149 | 0 | BN_free(bnOne); |
150 | 0 | size_I = vlen * 2; |
151 | 0 | } |
152 | | |
153 | 0 | EVP_MD_CTX_destroy(ctx); |
154 | 0 | free(I); |
155 | 0 | free(v); |
156 | |
|
157 | 0 | return 1; |
158 | 0 | } |