File: | s/cmd/dbtool/dbtool.c |
Warning: | line 697, column 5 Value stored to 'crv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | |
5 | /* |
6 | ** dbtool.c |
7 | ** |
8 | ** tool to dump the underlying encoding of a database. This tool duplicates |
9 | ** some private functions in softoken. It uses libsec and libutil, but no |
10 | ** other portions of NSS. It currently only works on sqlite databases. For |
11 | ** an even more primitive dump, use sqlite3 on the individual files. |
12 | ** |
13 | ** TODO: dump the meta data for the databases. |
14 | ** optionally dump more PKCS5 information (KDF/salt/iterations) |
15 | ** take a password and decode encrypted attributes/verify signed |
16 | ** attributes. |
17 | */ |
18 | #include <stdio.h> |
19 | #include <string.h> |
20 | |
21 | #if defined(WIN32) |
22 | #include "fcntl.h" |
23 | #include "io.h" |
24 | #endif |
25 | |
26 | /*#include "secutil.h" */ |
27 | /*#include "pk11pub.h" */ |
28 | |
29 | #if defined(XP_UNIX1) |
30 | #include <unistd.h> |
31 | #endif |
32 | |
33 | #include "nspr.h" |
34 | #include "prtypes.h" |
35 | #include "nss.h" |
36 | #include "secasn1.h" |
37 | #include "secder.h" |
38 | #include "pk11table.h" |
39 | #include "sftkdbt.h" |
40 | #include "sdb.h" |
41 | #include "secoid.h" |
42 | |
43 | #include "plgetopt.h" |
44 | |
45 | static char *progName; |
46 | |
47 | char *dbDir = NULL((void*)0); |
48 | |
49 | static void |
50 | Usage() |
51 | { |
52 | printf("Usage: %s [-c certprefix] [-k keyprefix] " |
53 | "[-V certversion] [-v keyversion]\n" |
54 | " [-d dbdir]\n", |
55 | progName); |
56 | printf("%-20s Directory with cert database (default is .)\n", |
57 | "-d certdir"); |
58 | printf("%-20s prefix for the cert database (default is \"\")\n", |
59 | "-c certprefix"); |
60 | printf("%-20s prefix for the key database (default is \"\")\n", |
61 | "-k keyprefix"); |
62 | printf("%-20s version of the cert database (default is 9)\n", |
63 | "-V certversion"); |
64 | printf("%-20s version of the key database (default is 4)\n", |
65 | "-v keyversion"); |
66 | exit(1); |
67 | } |
68 | #define SFTK_KEYDB_TYPE0x40000000 0x40000000 |
69 | #define SFTK_TOKEN_TYPE0x80000000 0x80000000 |
70 | |
71 | /* |
72 | * known attributes |
73 | */ |
74 | static const CK_ATTRIBUTE_TYPE known_attributes[] = { |
75 | CKA_CLASS0x00000000UL, CKA_TOKEN0x00000001UL, CKA_PRIVATE0x00000002UL, CKA_LABEL0x00000003UL, CKA_APPLICATION0x00000010UL, |
76 | CKA_VALUE0x00000011UL, CKA_OBJECT_ID0x00000012UL, CKA_CERTIFICATE_TYPE0x00000080UL, CKA_ISSUER0x00000081UL, |
77 | CKA_SERIAL_NUMBER0x00000082UL, CKA_AC_ISSUER0x00000083UL, CKA_OWNER0x00000084UL, CKA_ATTR_TYPES0x00000085UL, CKA_TRUSTED0x00000086UL, |
78 | CKA_CERTIFICATE_CATEGORY0x00000087UL, CKA_JAVA_MIDP_SECURITY_DOMAIN0x00000088UL, CKA_URL0x00000089UL, |
79 | CKA_HASH_OF_SUBJECT_PUBLIC_KEY0x0000008AUL, CKA_HASH_OF_ISSUER_PUBLIC_KEY0x0000008BUL, |
80 | CKA_CHECK_VALUE0x00000090UL, CKA_KEY_TYPE0x00000100UL, CKA_SUBJECT0x00000101UL, CKA_ID0x00000102UL, CKA_SENSITIVE0x00000103UL, |
81 | CKA_ENCRYPT0x00000104UL, CKA_DECRYPT0x00000105UL, CKA_WRAP0x00000106UL, CKA_UNWRAP0x00000107UL, CKA_SIGN0x00000108UL, CKA_SIGN_RECOVER0x00000109UL, |
82 | CKA_VERIFY0x0000010AUL, CKA_VERIFY_RECOVER0x0000010BUL, CKA_DERIVE0x0000010CUL, CKA_START_DATE0x00000110UL, CKA_END_DATE0x00000111UL, |
83 | CKA_MODULUS0x00000120UL, CKA_MODULUS_BITS0x00000121UL, CKA_PUBLIC_EXPONENT0x00000122UL, CKA_PRIVATE_EXPONENT0x00000123UL, |
84 | CKA_PRIME_10x00000124UL, CKA_PRIME_20x00000125UL, CKA_EXPONENT_10x00000126UL, CKA_EXPONENT_20x00000127UL, CKA_COEFFICIENT0x00000128UL, |
85 | CKA_PRIME0x00000130UL, CKA_SUBPRIME0x00000131UL, CKA_BASE0x00000132UL, CKA_PRIME_BITS0x00000133UL, |
86 | CKA_SUB_PRIME_BITS0x00000134UL, CKA_VALUE_BITS0x00000160UL, CKA_VALUE_LEN0x00000161UL, CKA_EXTRACTABLE0x00000162UL, |
87 | CKA_LOCAL0x00000163UL, CKA_NEVER_EXTRACTABLE0x00000164UL, CKA_ALWAYS_SENSITIVE0x00000165UL, |
88 | CKA_KEY_GEN_MECHANISM0x00000166UL, CKA_MODIFIABLE0x00000170UL, CKA_EC_PARAMS0x00000180UL, |
89 | CKA_EC_POINT0x00000181UL, CKA_SECONDARY_AUTH0x00000200UL, CKA_AUTH_PIN_FLAGS0x00000201UL, |
90 | CKA_ALWAYS_AUTHENTICATE0x00000202UL, CKA_WRAP_WITH_TRUSTED0x00000210UL, CKA_WRAP_TEMPLATE(0x40000000UL | 0x00000211UL), |
91 | CKA_UNWRAP_TEMPLATE(0x40000000UL | 0x00000212UL), CKA_HW_FEATURE_TYPE0x00000300UL, CKA_RESET_ON_INIT0x00000301UL, |
92 | CKA_HAS_RESET0x00000302UL, CKA_PIXEL_X0x00000400UL, CKA_PIXEL_Y0x00000401UL, CKA_RESOLUTION0x00000402UL, CKA_CHAR_ROWS0x00000403UL, |
93 | CKA_CHAR_COLUMNS0x00000404UL, CKA_COLOR0x00000405UL, CKA_BITS_PER_PIXEL0x00000406UL, CKA_CHAR_SETS0x00000480UL, |
94 | CKA_ENCODING_METHODS0x00000481UL, CKA_MIME_TYPES0x00000482UL, CKA_MECHANISM_TYPE0x00000500UL, |
95 | CKA_REQUIRED_CMS_ATTRIBUTES0x00000501UL, CKA_DEFAULT_CMS_ATTRIBUTES0x00000502UL, |
96 | CKA_SUPPORTED_CMS_ATTRIBUTES0x00000503UL, CKA_NSS_URL((0x80000000UL | 0x4E534350) + 1), CKA_NSS_EMAIL((0x80000000UL | 0x4E534350) + 2), |
97 | CKA_NSS_SMIME_INFO((0x80000000UL | 0x4E534350) + 3), CKA_NSS_SMIME_TIMESTAMP((0x80000000UL | 0x4E534350) + 4), |
98 | CKA_NSS_PKCS8_SALT((0x80000000UL | 0x4E534350) + 5), CKA_NSS_PASSWORD_CHECK((0x80000000UL | 0x4E534350) + 6), CKA_NSS_EXPIRES((0x80000000UL | 0x4E534350) + 7), |
99 | CKA_NSS_KRL((0x80000000UL | 0x4E534350) + 8), CKA_NSS_PQG_COUNTER((0x80000000UL | 0x4E534350) + 20), CKA_NSS_PQG_SEED((0x80000000UL | 0x4E534350) + 21), |
100 | CKA_NSS_PQG_H((0x80000000UL | 0x4E534350) + 22), CKA_NSS_PQG_SEED_BITS((0x80000000UL | 0x4E534350) + 23), CKA_NSS_MODULE_SPEC((0x80000000UL | 0x4E534350) + 24), |
101 | CKA_TRUST_DIGITAL_SIGNATURE(((0x80000000UL | 0x4E534350) + 0x2000) + 1), CKA_TRUST_NON_REPUDIATION(((0x80000000UL | 0x4E534350) + 0x2000) + 2), |
102 | CKA_TRUST_KEY_ENCIPHERMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 3), CKA_TRUST_DATA_ENCIPHERMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 4), |
103 | CKA_TRUST_KEY_AGREEMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 5), CKA_TRUST_KEY_CERT_SIGN(((0x80000000UL | 0x4E534350) + 0x2000) + 6), CKA_TRUST_CRL_SIGN(((0x80000000UL | 0x4E534350) + 0x2000) + 7), |
104 | CKA_TRUST_SERVER_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 8), CKA_TRUST_CLIENT_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 9), CKA_TRUST_CODE_SIGNING(((0x80000000UL | 0x4E534350) + 0x2000) + 10), |
105 | CKA_TRUST_EMAIL_PROTECTION(((0x80000000UL | 0x4E534350) + 0x2000) + 11), CKA_TRUST_IPSEC_END_SYSTEM(((0x80000000UL | 0x4E534350) + 0x2000) + 12), |
106 | CKA_TRUST_IPSEC_TUNNEL(((0x80000000UL | 0x4E534350) + 0x2000) + 13), CKA_TRUST_IPSEC_USER(((0x80000000UL | 0x4E534350) + 0x2000) + 14), CKA_TRUST_TIME_STAMPING(((0x80000000UL | 0x4E534350) + 0x2000) + 15), |
107 | CKA_TRUST_STEP_UP_APPROVED(((0x80000000UL | 0x4E534350) + 0x2000) + 16), CKA_CERT_SHA1_HASH(((0x80000000UL | 0x4E534350) + 0x2000) + 100), CKA_CERT_MD5_HASH(((0x80000000UL | 0x4E534350) + 0x2000) + 101), |
108 | CKA_NSS_DB0xD5A0DB00L, CKA_NSS_TRUST0x80000001L, CKA_NSS_OVERRIDE_EXTENSIONS((0x80000000UL | 0x4E534350) + 25), |
109 | CKA_PUBLIC_KEY_INFO0x00000129UL |
110 | }; |
111 | |
112 | static unsigned int known_attributes_size = sizeof(known_attributes) / |
113 | sizeof(known_attributes[0]); |
114 | |
115 | PRBool |
116 | isULONGAttribute(CK_ATTRIBUTE_TYPE type) |
117 | { |
118 | switch (type) { |
119 | case CKA_CERTIFICATE_CATEGORY0x00000087UL: |
120 | case CKA_CERTIFICATE_TYPE0x00000080UL: |
121 | case CKA_CLASS0x00000000UL: |
122 | case CKA_JAVA_MIDP_SECURITY_DOMAIN0x00000088UL: |
123 | case CKA_KEY_GEN_MECHANISM0x00000166UL: |
124 | case CKA_KEY_TYPE0x00000100UL: |
125 | case CKA_MECHANISM_TYPE0x00000500UL: |
126 | case CKA_MODULUS_BITS0x00000121UL: |
127 | case CKA_PRIME_BITS0x00000133UL: |
128 | case CKA_SUBPRIME_BITS0x00000134UL: |
129 | case CKA_VALUE_BITS0x00000160UL: |
130 | case CKA_VALUE_LEN0x00000161UL: |
131 | |
132 | case CKA_TRUST_DIGITAL_SIGNATURE(((0x80000000UL | 0x4E534350) + 0x2000) + 1): |
133 | case CKA_TRUST_NON_REPUDIATION(((0x80000000UL | 0x4E534350) + 0x2000) + 2): |
134 | case CKA_TRUST_KEY_ENCIPHERMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 3): |
135 | case CKA_TRUST_DATA_ENCIPHERMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 4): |
136 | case CKA_TRUST_KEY_AGREEMENT(((0x80000000UL | 0x4E534350) + 0x2000) + 5): |
137 | case CKA_TRUST_KEY_CERT_SIGN(((0x80000000UL | 0x4E534350) + 0x2000) + 6): |
138 | case CKA_TRUST_CRL_SIGN(((0x80000000UL | 0x4E534350) + 0x2000) + 7): |
139 | |
140 | case CKA_TRUST_SERVER_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 8): |
141 | case CKA_TRUST_CLIENT_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 9): |
142 | case CKA_TRUST_CODE_SIGNING(((0x80000000UL | 0x4E534350) + 0x2000) + 10): |
143 | case CKA_TRUST_EMAIL_PROTECTION(((0x80000000UL | 0x4E534350) + 0x2000) + 11): |
144 | case CKA_TRUST_IPSEC_END_SYSTEM(((0x80000000UL | 0x4E534350) + 0x2000) + 12): |
145 | case CKA_TRUST_IPSEC_TUNNEL(((0x80000000UL | 0x4E534350) + 0x2000) + 13): |
146 | case CKA_TRUST_IPSEC_USER(((0x80000000UL | 0x4E534350) + 0x2000) + 14): |
147 | case CKA_TRUST_TIME_STAMPING(((0x80000000UL | 0x4E534350) + 0x2000) + 15): |
148 | case CKA_TRUST_STEP_UP_APPROVED(((0x80000000UL | 0x4E534350) + 0x2000) + 16): |
149 | return PR_TRUE1; |
150 | default: |
151 | break; |
152 | } |
153 | return PR_FALSE0; |
154 | } |
155 | |
156 | /* are the attributes private? */ |
157 | static PRBool |
158 | isPrivateAttribute(CK_ATTRIBUTE_TYPE type) |
159 | { |
160 | switch (type) { |
161 | case CKA_VALUE0x00000011UL: |
162 | case CKA_PRIVATE_EXPONENT0x00000123UL: |
163 | case CKA_PRIME_10x00000124UL: |
164 | case CKA_PRIME_20x00000125UL: |
165 | case CKA_EXPONENT_10x00000126UL: |
166 | case CKA_EXPONENT_20x00000127UL: |
167 | case CKA_COEFFICIENT0x00000128UL: |
168 | return PR_TRUE1; |
169 | default: |
170 | break; |
171 | } |
172 | return PR_FALSE0; |
173 | } |
174 | |
175 | /* These attributes must be authenticated with an hmac. */ |
176 | static PRBool |
177 | isAuthenticatedAttribute(CK_ATTRIBUTE_TYPE type) |
178 | { |
179 | switch (type) { |
180 | case CKA_MODULUS0x00000120UL: |
181 | case CKA_PUBLIC_EXPONENT0x00000122UL: |
182 | case CKA_CERT_SHA1_HASH(((0x80000000UL | 0x4E534350) + 0x2000) + 100): |
183 | case CKA_CERT_MD5_HASH(((0x80000000UL | 0x4E534350) + 0x2000) + 101): |
184 | case CKA_TRUST_SERVER_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 8): |
185 | case CKA_TRUST_CLIENT_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 9): |
186 | case CKA_TRUST_EMAIL_PROTECTION(((0x80000000UL | 0x4E534350) + 0x2000) + 11): |
187 | case CKA_TRUST_CODE_SIGNING(((0x80000000UL | 0x4E534350) + 0x2000) + 10): |
188 | case CKA_TRUST_STEP_UP_APPROVED(((0x80000000UL | 0x4E534350) + 0x2000) + 16): |
189 | case CKA_NSS_OVERRIDE_EXTENSIONS((0x80000000UL | 0x4E534350) + 25): |
190 | return PR_TRUE1; |
191 | default: |
192 | break; |
193 | } |
194 | return PR_FALSE0; |
195 | } |
196 | |
197 | /* |
198 | * convert a database ulong back to a native ULONG. (reverse of the above |
199 | * function. |
200 | */ |
201 | static CK_ULONG |
202 | sdbULong2ULong(unsigned char *data) |
203 | { |
204 | int i; |
205 | CK_ULONG value = 0; |
206 | |
207 | for (i = 0; i < SDB_ULONG_SIZE4; i++) { |
208 | value |= (((CK_ULONG)data[i]) << (SDB_ULONG_SIZE4 - 1 - i) * PR_BITS_PER_BYTE8); |
209 | } |
210 | return value; |
211 | } |
212 | |
213 | /* PBE defines and functions */ |
214 | SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
215 | |
216 | typedef struct EncryptedDataInfoStr { |
217 | SECAlgorithmID algorithm; |
218 | SECItem encryptedData; |
219 | } EncryptedDataInfo; |
220 | |
221 | static const SEC_ASN1Template encryptedDataInfoTemplate[] = { |
222 | { SEC_ASN1_SEQUENCE0x10, |
223 | 0, NULL((void*)0), sizeof(EncryptedDataInfo) }, |
224 | { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, |
225 | offsetof(EncryptedDataInfo, algorithm)__builtin_offsetof(EncryptedDataInfo, algorithm), |
226 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util }, |
227 | { SEC_ASN1_OCTET_STRING0x04, |
228 | offsetof(EncryptedDataInfo, encryptedData)__builtin_offsetof(EncryptedDataInfo, encryptedData) }, |
229 | { 0 } |
230 | }; |
231 | |
232 | typedef struct PBEParameterStr { |
233 | SECAlgorithmID prfAlg; |
234 | SECItem salt; |
235 | SECItem iteration; |
236 | SECItem keyLength; |
237 | } PBEParameter; |
238 | |
239 | static const SEC_ASN1Template pkcs5V1PBEParameterTemplate[] = { |
240 | { SEC_ASN1_SEQUENCE0x10, |
241 | 0, NULL((void*)0), sizeof(PBEParameter) }, |
242 | { SEC_ASN1_OCTET_STRING0x04, |
243 | offsetof(PBEParameter, salt)__builtin_offsetof(PBEParameter, salt) }, |
244 | { SEC_ASN1_INTEGER0x02, |
245 | offsetof(PBEParameter, iteration)__builtin_offsetof(PBEParameter, iteration) }, |
246 | { 0 } |
247 | }; |
248 | |
249 | static const SEC_ASN1Template pkcs12V2PBEParameterTemplate[] = { |
250 | { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(PBEParameter) }, |
251 | { SEC_ASN1_OCTET_STRING0x04, offsetof(PBEParameter, salt)__builtin_offsetof(PBEParameter, salt) }, |
252 | { SEC_ASN1_INTEGER0x02, offsetof(PBEParameter, iteration)__builtin_offsetof(PBEParameter, iteration) }, |
253 | { 0 } |
254 | }; |
255 | |
256 | static const SEC_ASN1Template pkcs5V2PBEParameterTemplate[] = { |
257 | { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(PBEParameter) }, |
258 | /* this is really a choice, but since we don't understand any other |
259 | * choice, just inline it. */ |
260 | { SEC_ASN1_OCTET_STRING0x04, offsetof(PBEParameter, salt)__builtin_offsetof(PBEParameter, salt) }, |
261 | { SEC_ASN1_INTEGER0x02, offsetof(PBEParameter, iteration)__builtin_offsetof(PBEParameter, iteration) }, |
262 | { SEC_ASN1_INTEGER0x02, offsetof(PBEParameter, keyLength)__builtin_offsetof(PBEParameter, keyLength) }, |
263 | { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, |
264 | offsetof(PBEParameter, prfAlg)__builtin_offsetof(PBEParameter, prfAlg), |
265 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util }, |
266 | { 0 } |
267 | }; |
268 | |
269 | typedef struct Pkcs5v2PBEParameterStr { |
270 | SECAlgorithmID keyParams; /* parameters of the key generation */ |
271 | SECAlgorithmID algParams; /* parameters for the encryption or mac op */ |
272 | } Pkcs5v2PBEParameter; |
273 | |
274 | static const SEC_ASN1Template pkcs5v2PBES2ParameterTemplate[] = { |
275 | { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(Pkcs5v2PBEParameter) }, |
276 | { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, |
277 | offsetof(Pkcs5v2PBEParameter, keyParams)__builtin_offsetof(Pkcs5v2PBEParameter, keyParams), |
278 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util }, |
279 | { SEC_ASN1_INLINE0x00800 | SEC_ASN1_XTRN0, |
280 | offsetof(Pkcs5v2PBEParameter, algParams)__builtin_offsetof(Pkcs5v2PBEParameter, algParams), |
281 | SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)SECOID_AlgorithmIDTemplate_Util }, |
282 | { 0 } |
283 | }; |
284 | |
285 | static inline PRBool |
286 | isPKCS12PBE(SECOidTag alg) |
287 | { |
288 | switch (alg) { |
289 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC: |
290 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC: |
291 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC: |
292 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC: |
293 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4: |
294 | case SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4: |
295 | return PR_TRUE1; |
296 | default: |
297 | break; |
298 | } |
299 | return PR_FALSE0; |
300 | } |
301 | |
302 | /* helper functions */ |
303 | |
304 | /* output an NSS specific attribute or name that wasn't found in our |
305 | * pkcs #11 table */ |
306 | const char * |
307 | makeNSSVendorName(CK_ATTRIBUTE_TYPE attribute, const char *nameType) |
308 | { |
309 | static char nss_name[256]; |
310 | const char *name = NULL((void*)0); |
311 | if ((attribute >= CKA_NSS(0x80000000UL | 0x4E534350)) && (attribute < 0xffffffffUL)) { |
312 | sprintf(nss_name, "%s+%d", nameType, (int)(attribute - CKA_NSS(0x80000000UL | 0x4E534350))); |
313 | name = nss_name; |
314 | } |
315 | return name; |
316 | } |
317 | |
318 | /* turn and attribute into a name */ |
319 | const char * |
320 | AttributeName(CK_ATTRIBUTE_TYPE attribute) |
321 | { |
322 | const char *name = getNameFromAttribute(attribute); |
323 | if (!name) { |
324 | name = makeNSSVendorName(attribute, "CKA_NSS"); |
325 | } |
326 | |
327 | return name ? name : "UNKNOWN_ATTRIBUTE_TYPE"; |
328 | } |
329 | |
330 | /* turn and error code into a name */ |
331 | const char * |
332 | ErrorName(CK_RV crv) |
333 | { |
334 | const char *error = getName(crv, ConstResult); |
335 | if (!error) { |
336 | error = makeNSSVendorName(crv, "CKR_NSS"); |
337 | } |
338 | return error ? error : "UNKNOWN_ERROR"; |
339 | } |
340 | |
341 | /* turn an oud tag into a string */ |
342 | const char * |
343 | oid2string(SECOidTag alg) |
344 | { |
345 | const char *oidstring = SECOID_FindOIDTagDescriptionSECOID_FindOIDTagDescription_Util(alg); |
346 | const char *def = "Invalid oid tag"; /* future build a dotted oid string value here */ |
347 | return oidstring ? oidstring : def; |
348 | } |
349 | |
350 | /* dump an arbitary data blob. Dump it has hex with ascii on the side */ |
351 | #define ASCCHAR(val)((val) >= ' ' && (val) <= 0x7e ? (val) : '.') ((val) >= ' ' && (val) <= 0x7e ? (val) : '.') |
352 | #define LINE_LENGTH16 16 |
353 | void |
354 | dumpValue(const unsigned char *v, int len) |
355 | { |
356 | int i, next = 0; |
357 | char string[LINE_LENGTH16 + 1]; |
358 | char space[LINE_LENGTH16 * 2 + 1]; |
359 | char *nl = ""; |
360 | char *sp = ""; |
361 | PORT_Memsetmemset(string, 0, sizeof(string)); |
362 | |
363 | for (i = 0; i < len; i++) { |
364 | if ((i % LINE_LENGTH16) == 0) { |
365 | printf("%s%s%s ", sp, string, nl); |
366 | PORT_Memsetmemset(string, 0, sizeof(string)); |
367 | next = 0; |
368 | nl = "\n"; |
369 | sp = " "; |
370 | } |
371 | printf("%02x", v[i]); |
372 | string[next++] = ASCCHAR(v[i])((v[i]) >= ' ' && (v[i]) <= 0x7e ? (v[i]) : '.' ); |
373 | } |
374 | PORT_Memsetmemset(space, 0, sizeof(space)); |
375 | i = LINE_LENGTH16 - (len % LINE_LENGTH16); |
376 | if (i != LINE_LENGTH16) { |
377 | int j; |
378 | for (j = 0; j < i; j++) { |
379 | space[j * 2] = ' '; |
380 | space[j * 2 + 1] = ' '; |
381 | } |
382 | } |
383 | printf("%s%s%s%s", space, sp, string, nl); |
384 | } |
385 | |
386 | /* dump a PKCS5/12 PBE blob */ |
387 | void |
388 | dumpPKCS(unsigned char *val, CK_ULONG len, PRBool *hasSig) |
389 | { |
390 | EncryptedDataInfo edi; |
391 | SECStatus rv; |
392 | SECItem data; |
393 | PLArenaPool *arena; |
394 | SECOidTag alg, prfAlg; |
395 | PBEParameter pbeParam; |
396 | unsigned char zero = 0; |
397 | const SEC_ASN1Template *template = pkcs5V1PBEParameterTemplate; |
398 | int iter, keyLen, i; |
399 | |
400 | if (hasSig) { |
401 | *hasSig = PR_FALSE0; |
402 | } |
403 | |
404 | data.data = val; |
405 | data.len = len; |
406 | arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048)); |
407 | if (arena == NULL((void*)0)) { |
408 | printf("Couldn't allocate arena\n"); |
409 | return; |
410 | } |
411 | |
412 | /* initialize default values */ |
413 | PORT_Memsetmemset(&pbeParam, 0, sizeof(pbeParam)); |
414 | pbeParam.keyLength.data = &zero; |
415 | pbeParam.keyLength.len = sizeof(zero); |
416 | SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(arena, &pbeParam.prfAlg, SEC_OID_SHA1, NULL((void*)0)); |
417 | |
418 | /* first crack the encrypted data from the PBE algorithm ID */ |
419 | rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, &edi, encryptedDataInfoTemplate, &data); |
420 | if (rv != SECSuccess) { |
421 | printf("Encrypted Data, failed to decode\n"); |
422 | dumpValue(val, len); |
423 | PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0); |
424 | return; |
425 | } |
426 | /* now use the pbe secalg to dump info on the pbe */ |
427 | alg = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&edi.algorithm); |
428 | if ((alg == SEC_OID_PKCS5_PBES2) || (alg == SEC_OID_PKCS5_PBMAC1)) { |
429 | Pkcs5v2PBEParameter param; |
430 | SECOidTag palg; |
431 | const char *typeName = (alg == SEC_OID_PKCS5_PBES2) ? "Encrypted Data PBES2" : "Mac Data PBMAC1"; |
432 | |
433 | rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, ¶m, |
434 | pkcs5v2PBES2ParameterTemplate, |
435 | &edi.algorithm.parameters); |
436 | if (rv != SECSuccess) { |
437 | printf("%s, failed to decode\n", typeName); |
438 | dumpValue(val, len); |
439 | PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0); |
440 | return; |
441 | } |
442 | palg = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(¶m.algParams); |
443 | printf("%s alg=%s ", typeName, oid2string(palg)); |
444 | if (hasSig && palg == SEC_OID_AES_256_CBC) { |
445 | *hasSig = PR_TRUE1; |
446 | } |
447 | template = pkcs5V2PBEParameterTemplate; |
448 | edi.algorithm.parameters = param.keyParams.parameters; |
449 | } else { |
450 | printf("Encrypted Data alg=%s ", oid2string(alg)); |
451 | if (alg == SEC_OID_PKCS5_PBKDF2) { |
452 | template = pkcs5V2PBEParameterTemplate; |
453 | } else if (isPKCS12PBE(alg)) { |
454 | template = pkcs12V2PBEParameterTemplate; |
455 | } else { |
456 | template = pkcs5V1PBEParameterTemplate; |
457 | } |
458 | } |
459 | rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, &pbeParam, |
460 | template, |
461 | &edi.algorithm.parameters); |
462 | if (rv != SECSuccess) { |
463 | printf("( failed to decode params)\n"); |
464 | PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0); |
465 | return; |
466 | } |
467 | /* dump the pbe parmeters */ |
468 | iter = DER_GetIntegerDER_GetInteger_Util(&pbeParam.iteration); |
469 | keyLen = DER_GetIntegerDER_GetInteger_Util(&pbeParam.keyLength); |
470 | prfAlg = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&pbeParam.prfAlg); |
471 | printf("(prf=%s iter=%d keyLen=%d salt=0x", |
472 | oid2string(prfAlg), iter, keyLen); |
473 | for (i = 0; i < pbeParam.salt.len; i++) |
474 | printf("%02x", pbeParam.salt.data[i]); |
475 | printf(")\n"); |
476 | /* finally dump the raw encrypted data */ |
477 | dumpValue(edi.encryptedData.data, edi.encryptedData.len); |
478 | PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0); |
479 | } |
480 | |
481 | /* dump a long attribute, convert to an unsigned long. PKCS #11 Longs are |
482 | * limited to 32 bits by the spec, even if the CK_ULONG is longer */ |
483 | void |
484 | dumpLongAttribute(CK_ATTRIBUTE_TYPE type, CK_ULONG value) |
485 | { |
486 | const char *nameType = "CK_NSS"; |
487 | ConstType constType = ConstNone; |
488 | const char *valueName = NULL((void*)0); |
489 | |
490 | switch (type) { |
491 | case CKA_CLASS0x00000000UL: |
492 | nameType = "CKO_NSS"; |
493 | constType = ConstObject; |
494 | break; |
495 | case CKA_CERTIFICATE_TYPE0x00000080UL: |
496 | nameType = "CKC_NSS"; |
497 | constType = ConstCertType; |
498 | break; |
499 | case CKA_KEY_TYPE0x00000100UL: |
500 | nameType = "CKK_NSS"; |
501 | constType = ConstKeyType; |
502 | break; |
503 | case CKA_MECHANISM_TYPE0x00000500UL: |
504 | nameType = "CKM_NSS"; |
505 | constType = ConstMechanism; |
506 | break; |
507 | case CKA_TRUST_SERVER_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 8): |
508 | case CKA_TRUST_CLIENT_AUTH(((0x80000000UL | 0x4E534350) + 0x2000) + 9): |
509 | case CKA_TRUST_CODE_SIGNING(((0x80000000UL | 0x4E534350) + 0x2000) + 10): |
510 | case CKA_TRUST_EMAIL_PROTECTION(((0x80000000UL | 0x4E534350) + 0x2000) + 11): |
511 | case CKA_TRUST_IPSEC_END_SYSTEM(((0x80000000UL | 0x4E534350) + 0x2000) + 12): |
512 | case CKA_TRUST_IPSEC_TUNNEL(((0x80000000UL | 0x4E534350) + 0x2000) + 13): |
513 | case CKA_TRUST_IPSEC_USER(((0x80000000UL | 0x4E534350) + 0x2000) + 14): |
514 | case CKA_TRUST_TIME_STAMPING(((0x80000000UL | 0x4E534350) + 0x2000) + 15): |
515 | nameType = "CKT_NSS"; |
516 | constType = ConstTrust; |
517 | break; |
518 | default: |
519 | break; |
520 | } |
521 | /* if value has a symbolic name, use it */ |
522 | if (constType != ConstNone) { |
523 | valueName = getName(value, constType); |
524 | } |
525 | if (!valueName) { |
526 | valueName = makeNSSVendorName(value, nameType); |
527 | } |
528 | if (!valueName) { |
529 | printf("%d (0x%08x)\n", (int)value, (int)value); |
530 | } else { |
531 | printf("%s (0x%08x)\n", valueName, (int)value); |
532 | } |
533 | } |
534 | |
535 | /* dump a signature for an object */ |
536 | static const char META_SIG_TEMPLATE[] = "sig_%s_%08x_%08x"; |
537 | void |
538 | dumpSignature(CK_ATTRIBUTE_TYPE attribute, SDB *keydb, PRBool isKey, |
539 | CK_OBJECT_HANDLE objectID, PRBool force) |
540 | { |
541 | char id[30]; |
542 | CK_RV crv; |
543 | SECItem signText; |
544 | unsigned char signData[SDB_MAX_META_DATA_LEN256]; |
545 | |
546 | if (!force && !isAuthenticatedAttribute(attribute)) { |
547 | return; |
548 | } |
549 | sprintf(id, META_SIG_TEMPLATE, |
550 | isKey ? "key" : "cert", |
551 | (unsigned int)objectID, (unsigned int)attribute); |
552 | printf(" Signature %s:", id); |
553 | signText.data = signData; |
554 | signText.len = sizeof(signData); |
555 | |
556 | crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL((void*)0)); |
557 | if ((crv != CKR_OK0x00000000UL) && isKey) { |
558 | sprintf(id, META_SIG_TEMPLATE, |
559 | isKey ? "key" : "cert", (unsigned int)(objectID | SFTK_KEYDB_TYPE0x40000000 | SFTK_TOKEN_TYPE0x80000000), |
560 | (unsigned int)attribute); |
561 | crv = (*keydb->sdb_GetMetaData)(keydb, id, &signText, NULL((void*)0)); |
562 | } |
563 | if (crv != CKR_OK0x00000000UL) { |
564 | printf(" FAILED %s with %s (0x%08x)\n", id, ErrorName(crv), (int)crv); |
565 | return; |
566 | } |
567 | dumpPKCS(signText.data, signText.len, NULL((void*)0)); |
568 | return; |
569 | } |
570 | |
571 | /* dump an attribute. use the helper functions above */ |
572 | void |
573 | dumpAttribute(CK_ATTRIBUTE *template, SDB *keydb, PRBool isKey, |
574 | CK_OBJECT_HANDLE id) |
575 | { |
576 | CK_ATTRIBUTE_TYPE attribute = template->type; |
577 | printf(" %s(0x%08x): ", AttributeName(attribute), (int)attribute); |
578 | if (template->pValue == NULL((void*)0)) { |
579 | printf("NULL (%d)\n", (int)template->ulValueLen); |
580 | return; |
581 | } |
582 | if (template->ulValueLen == SDB_ULONG_SIZE4 && isULONGAttribute(attribute)) { |
583 | CK_ULONG value = sdbULong2ULong(template->pValue); |
584 | dumpLongAttribute(attribute, value); |
585 | return; |
586 | } |
587 | if (template->ulValueLen == 1) { |
588 | unsigned char val = *(unsigned char *)template->pValue; |
589 | switch (val) { |
590 | case 0: |
591 | printf("CK_FALSE\n"); |
592 | break; |
593 | case 1: |
594 | printf("CK_TRUE\n"); |
595 | break; |
596 | default: |
597 | printf("%d 0x%02x %c\n", val, val, ASCCHAR(val)((val) >= ' ' && (val) <= 0x7e ? (val) : '.')); |
598 | break; |
599 | } |
600 | return; |
601 | } |
602 | if (isKey && isPrivateAttribute(attribute)) { |
603 | PRBool hasSig = PR_FALSE0; |
604 | dumpPKCS(template->pValue, template->ulValueLen, &hasSig); |
605 | if (hasSig) { |
606 | dumpSignature(attribute, keydb, isKey, id, PR_TRUE1); |
607 | } |
608 | return; |
609 | } |
610 | if (template->ulValueLen == 0) { |
611 | printf("empty"); |
612 | } |
613 | printf("\n"); |
614 | dumpValue(template->pValue, template->ulValueLen); |
615 | } |
616 | |
617 | /* dump all the attributes in an object */ |
618 | void |
619 | dumpObject(CK_OBJECT_HANDLE id, SDB *db, SDB *keydb, PRBool isKey) |
620 | { |
621 | CK_RV crv; |
622 | int i; |
623 | CK_ATTRIBUTE template; |
624 | char buffer[2048]; |
625 | char *alloc = NULL((void*)0); |
626 | |
627 | printf(" Object 0x%08x:\n", (int)id); |
628 | for (i = 0; i < known_attributes_size; i++) { |
629 | CK_ATTRIBUTE_TYPE attribute = known_attributes[i]; |
630 | template.type = attribute; |
631 | template.pValue = NULL((void*)0); |
632 | template.ulValueLen = 0; |
633 | crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); |
634 | |
635 | if (crv != CKR_OK0x00000000UL) { |
636 | if (crv != CKR_ATTRIBUTE_TYPE_INVALID0x00000012UL) { |
637 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), " " |
638 | "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", |
639 | AttributeName(attribute), (int)attribute, |
640 | ErrorName(crv), (int)crv); |
641 | } |
642 | continue; |
643 | } |
644 | |
645 | if (template.ulValueLen < sizeof(buffer)) { |
646 | template.pValue = buffer; |
647 | } else { |
648 | alloc = PORT_AllocPORT_Alloc_Util(template.ulValueLen); |
649 | template.pValue = alloc; |
650 | } |
651 | if (template.pValue == NULL((void*)0)) { |
652 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), " " |
653 | "Could allocate %d bytes for Attribute %s (0x%08x)\n", |
654 | (int)template.ulValueLen, |
655 | AttributeName(attribute), (int)attribute); |
656 | continue; |
657 | } |
658 | crv = (*db->sdb_GetAttributeValue)(db, id, &template, 1); |
659 | |
660 | if (crv != CKR_OK0x00000000UL) { |
661 | if (crv != CKR_ATTRIBUTE_TYPE_INVALID0x00000012UL) { |
662 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), " " |
663 | "Get Attribute %s (0x%08x):FAILED\"%s\"(0x%08x)\n", |
664 | AttributeName(attribute), (int)attribute, |
665 | ErrorName(crv), (int)crv); |
666 | } |
667 | if (alloc) { |
668 | PORT_FreePORT_Free_Util(alloc); |
669 | alloc = NULL((void*)0); |
670 | } |
671 | continue; |
672 | } |
673 | |
674 | dumpAttribute(&template, keydb, isKey, id); |
675 | dumpSignature(template.type, keydb, isKey, id, PR_FALSE0); |
676 | if (alloc) { |
677 | PORT_FreePORT_Free_Util(alloc); |
678 | alloc = NULL((void*)0); |
679 | } |
680 | } |
681 | } |
682 | |
683 | /* dump all the objects in a database */ |
684 | void |
685 | dumpDB(SDB *db, const char *name, SDB *keydb, PRBool isKey) |
686 | { |
687 | SDBFind *findHandle = NULL((void*)0); |
688 | CK_BBOOL isTrue = 1; |
689 | CK_ATTRIBUTE allObjectTemplate = { CKA_TOKEN0x00000001UL, NULL((void*)0), 1 }; |
690 | CK_ULONG allObjectTemplateCount = 1; |
691 | PRBool recordFound = PR_FALSE0; |
692 | CK_RV crv = CKR_OK0x00000000UL; |
693 | CK_ULONG objectCount = 0; |
694 | printf("%s:\n", name); |
695 | |
696 | allObjectTemplate.pValue = &isTrue; |
697 | crv = (*db->sdb_FindObjectsInit)(db, &allObjectTemplate, |
Value stored to 'crv' is never read | |
698 | allObjectTemplateCount, &findHandle); |
699 | do { |
700 | CK_OBJECT_HANDLE id; |
701 | recordFound = PR_FALSE0; |
702 | crv = (*db->sdb_FindObjects)(db, findHandle, &id, 1, &objectCount); |
703 | if ((crv == CKR_OK0x00000000UL) && (objectCount == 1)) { |
704 | recordFound = PR_TRUE1; |
705 | dumpObject(id, db, keydb, isKey); |
706 | } |
707 | } while (recordFound); |
708 | if (crv != CKR_OK0x00000000UL) { |
709 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), |
710 | "Last record return PKCS #11 error = %s (0x%08x)\n", |
711 | ErrorName(crv), (int)crv); |
712 | } |
713 | (*db->sdb_FindObjectsFinal)(db, findHandle); |
714 | } |
715 | |
716 | static char * |
717 | secu_ConfigDirectory(const char *base) |
718 | { |
719 | static PRBool initted = PR_FALSE0; |
720 | const char *dir = ".netscape"; |
721 | char *home; |
722 | static char buf[1000]; |
723 | |
724 | if (initted) |
725 | return buf; |
726 | |
727 | if (base == NULL((void*)0) || *base == 0) { |
728 | home = PR_GetEnvSecure("HOME"); |
729 | if (!home) |
730 | home = ""; |
731 | |
732 | if (*home && home[strlen(home) - 1] == '/') |
733 | sprintf(buf, "%.900s%s", home, dir); |
734 | else |
735 | sprintf(buf, "%.900s/%s", home, dir); |
736 | } else { |
737 | sprintf(buf, "%.900s", base); |
738 | if (buf[strlen(buf) - 1] == '/') |
739 | buf[strlen(buf) - 1] = 0; |
740 | } |
741 | |
742 | initted = PR_TRUE1; |
743 | return buf; |
744 | } |
745 | |
746 | int |
747 | main(int argc, char **argv) |
748 | { |
749 | PLOptState *optstate; |
750 | PLOptStatus optstatus; |
751 | char *certPrefix = "", *keyPrefix = ""; |
752 | int cert_version = 9; |
753 | int key_version = 4; |
754 | SDB *certdb = NULL((void*)0); |
755 | SDB *keydb = NULL((void*)0); |
756 | PRBool isNew = PR_FALSE0; |
757 | |
758 | CK_RV crv; |
759 | |
760 | progName = strrchr(argv[0], '/'); |
761 | if (!progName) |
762 | progName = strrchr(argv[0], '\\'); |
763 | progName = progName ? progName + 1 : argv[0]; |
764 | |
765 | optstate = PL_CreateOptState(argc, argv, "d:c:k:v:V:h"); |
766 | |
767 | while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
768 | switch (optstate->option) { |
769 | case 'h': |
770 | default: |
771 | Usage(); |
772 | break; |
773 | |
774 | case 'd': |
775 | dbDir = PORT_StrdupPORT_Strdup_Util(optstate->value); |
776 | break; |
777 | |
778 | case 'c': |
779 | certPrefix = PORT_StrdupPORT_Strdup_Util(optstate->value); |
780 | break; |
781 | |
782 | case 'k': |
783 | keyPrefix = PORT_StrdupPORT_Strdup_Util(optstate->value); |
784 | break; |
785 | |
786 | case 'v': |
787 | key_version = atoi(optstate->value); |
788 | break; |
789 | |
790 | case 'V': |
791 | cert_version = atoi(optstate->value); |
792 | break; |
793 | } |
794 | } |
795 | PL_DestroyOptState(optstate); |
796 | if (optstatus == PL_OPT_BAD) |
797 | Usage(); |
798 | |
799 | if (dbDir) { |
800 | char *tmp = dbDir; |
801 | dbDir = secu_ConfigDirectory(tmp); |
802 | PORT_FreePORT_Free_Util(tmp); |
803 | } else { |
804 | dbDir = secu_ConfigDirectory(NULL((void*)0)); |
805 | } |
806 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), "dbdir selected is %s\n\n", dbDir); |
807 | |
808 | if (dbDir[0] == '\0') { |
809 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), |
810 | "ERROR: Directory \"%s\" does not exist.\n", dbDir); |
811 | return 1; |
812 | } |
813 | |
814 | PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); |
815 | SECOID_Init(); |
816 | |
817 | crv = s_open(dbDir, certPrefix, keyPrefix, cert_version, key_version, |
818 | SDB_RDONLY1, &certdb, &keydb, &isNew); |
819 | if (crv != CKR_OK0x00000000UL) { |
820 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), |
821 | "Couldn't open databased in %s, error=%s (0x%08x)\n", |
822 | dbDir, ErrorName(crv), (int)crv); |
823 | return 1; |
824 | } |
825 | |
826 | /* now dump the objects in the cert database */ |
827 | dumpDB(certdb, "CertDB", keydb, PR_FALSE0); |
828 | dumpDB(keydb, "KeyDB", keydb, PR_TRUE1); |
829 | return 0; |
830 | } |