2 * p12Reencode - take a p12 PFX, decode and reencode
4 #include <Security/SecImportExport.h>\ 1
5 #include <Security/Security.h>
8 #include <security_cdsa_utils/cuFileIo.h>
9 #include <utilLib/common.h>
11 static void usage(char **argv
)
13 printf("Usage: %s pfx password keychain1 keychain2 [l=loops] [q(uiet)] "
14 "[v(erbose)]\n", argv
[0]);
21 static void writeBlobs(CFDataRef pfx1
, CFDataRef pfx2
)
23 writeFile("pfx1.der", CFDataGetBytePtr(pfx1
), CFDataGetLength(pfx1
));
24 writeFile("pfx2.der", CFDataGetBytePtr(pfx2
), CFDataGetLength(pfx2
));
25 printf("...wrote %u bytes to pfx1.der, %u bytes to pfx2.der\n",
26 CFDataGetLength(pfx1
), CFDataGetLength(pfx2
));
29 #define writeBlobs(p1, p2)
33 /* Not possible using import/export API */
34 /* compare attrs, all of which are optional */
35 static int compareAttrs(
36 CFStringRef refFriendlyName
,
37 CFDataRef refLocalKeyId
,
38 CFStringRef testFriendlyName
,
39 CFDataRef testLocalKeyId
,
43 if(refFriendlyName
== NULL
) {
44 if(testFriendlyName
!= NULL
) {
45 printf("****s refFriendlyName NULL, testFriendlyName "
46 "non-NULL\n", itemType
);
47 return testError(quiet
);
51 CFComparisonResult res
= CFStringCompare(refFriendlyName
,
53 if(res
!= kCFCompareEqualTo
) {
54 printf("***%s friendlyName Miscompare\n", itemType
);
55 return testError(quiet
);
59 if(refLocalKeyId
== NULL
) {
60 if(testLocalKeyId
!= NULL
) {
61 printf("****s refLocalKeyId NULL, testLocalKeyId "
62 "non-NULL\n", itemType
);
63 return testError(quiet
);
67 if(compareCfData(refLocalKeyId
, testLocalKeyId
)) {
68 printf("***%s localKeyId Miscompare\n", itemType
);
69 return testError(quiet
);
73 /* release the attrs */
75 CFRelease(refFriendlyName
);
78 CFRelease(refLocalKeyId
);
80 if(testFriendlyName
) {
81 CFRelease(testFriendlyName
);
84 CFRelease(testLocalKeyId
);
90 static void setUpKeyParams(
91 SecKeyImportExportParameters
&keyParams
,
94 memset(&keyParams
, 0, sizeof(keyParams
));
95 keyParams
.version
= SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION
;
96 keyParams
.passphrase
= pwd
;
100 * Basic import/export: convert between CFArray of keychain items and a CFDataRef
102 static OSStatus
p12Import(
105 SecKeychainRef kcRef
,
106 CFArrayRef
*outArray
)
108 SecKeyImportExportParameters keyParams
;
109 setUpKeyParams(keyParams
, pwd
);
111 SecExternalFormat format
= kSecFormatPKCS12
;
113 ortn
= SecKeychainItemImport(pfx
, NULL
, &format
, NULL
, 0, &keyParams
,
116 cssmPerror("SecKeychainItemImport", ortn
);
121 static OSStatus
p12Export(
126 SecKeyImportExportParameters keyParams
;
127 setUpKeyParams(keyParams
, pwd
);
130 ortn
= SecKeychainItemExport(inArray
, kSecFormatPKCS12
, 0, &keyParams
, pfx
);
132 cssmPerror("SecKeychainItemExport", ortn
);
138 * Compare two CFArrayRefs containing various items, subsequent to decode. Returns
139 * nonzero if they differ.
141 * As of April 9 2004, we do NOT see CRLs so we don't compare them. I think
142 * we need a SecCRLRef...
144 static int compareDecodedArrays(
146 CFArrayRef testArray
,
152 CFIndex numRefItems
= CFArrayGetCount(refArray
);
153 CFIndex numTestItems
= CFArrayGetCount(testArray
);
154 if(numRefItems
!= numTestItems
) {
155 printf("***item count mismatch: ref %ld test %ld\n",
156 numRefItems
, numTestItems
);
159 for(CFIndex dex
=0; dex
<numRefItems
; dex
++) {
160 CFTypeRef refItem
= CFArrayGetValueAtIndex(refArray
, dex
);
161 CFTypeRef testItem
= CFArrayGetValueAtIndex(testArray
, dex
);
162 CFTypeID theType
= CFGetTypeID(refItem
);
163 if(theType
!= CFGetTypeID(testItem
)) {
164 printf("***item type mismatch: ref %ld test %ld\n",
165 theType
, CFGetTypeID(testItem
));
168 if(theType
== SecCertificateGetTypeID()) {
169 /* cert: compare raw data */
172 ortn
= SecCertificateGetData((SecCertificateRef
)refItem
, &refData
);
174 cssmPerror("SecCertificateGetData", ortn
);
177 ortn
= SecCertificateGetData((SecCertificateRef
)testItem
, &testData
);
179 cssmPerror("SecCertificateGetData", ortn
);
182 if(!appCompareCssmData(&refData
, &testData
)) {
183 printf("***Data miscompare on cert %ld\n", dex
);
184 ourRtn
= testError(quiet
);
190 else if(theType
== SecKeyGetTypeID()) {
191 /* Keys - an inexact science to be sure since we don't attempt
192 * to access the raw key material */
194 const CSSM_KEY
*refKey
;
195 ortn
= SecKeyGetCSSMKey((SecKeyRef
)refItem
, &refKey
);
197 cssmPerror("SecKeyGetCSSMKey", ortn
);
200 const CSSM_KEY
*testKey
;
201 ortn
= SecKeyGetCSSMKey((SecKeyRef
)testItem
, &testKey
);
203 cssmPerror("SecPkcs12GetCssmPrivateKey", ortn
);
207 /* compare key sizes and algorithm */
208 if(refKey
->KeyHeader
.LogicalKeySizeInBits
!=
209 testKey
->KeyHeader
.LogicalKeySizeInBits
) {
210 printf("***Key size miscompare on Key %ld\n", dex
);
211 ourRtn
= testError(quiet
);
216 if(refKey
->KeyHeader
.AlgorithmId
!=
217 testKey
->KeyHeader
.AlgorithmId
) {
218 printf("***AlgorithmId miscompare on Key %ld\n", dex
);
219 ourRtn
= testError(quiet
);
226 /* this program may need work here. e.g. for SecCRLRefs */
227 printf("***Unknown type ID (%ld)\n", theType
);
235 int main(int argc
, char **argv
)
239 SecKeychainRef kcRef1
= nil
; // reference, 1st import destination
240 SecKeychainRef kcRef2
= nil
; // subsequent import destination
242 CSSM_BOOL quiet
= CSSM_FALSE
;
244 bool verbose
= false;
245 bool doPause
= false;
254 if(readFile(argv
[1], &pfx
, &pfxLen
)) {
255 printf("***Error reading PFX from %s. Aborting.\n", argv
[1]);
258 CFStringRef pwd
= CFStringCreateWithCString(NULL
, argv
[2],
259 kCFStringEncodingASCII
);
261 printf("Bad password (%s)\n", argv
[2]);
265 OSStatus ortn
= SecKeychainOpen(kcName
, &kcRef1
);
267 cssmPerror("SecKeychainOpen", ortn
);
271 ortn
= SecKeychainOpen(kcName
, &kcRef2
);
273 cssmPerror("SecKeychainOpen", ortn
);
277 for(i
=5; i
<argc
; i
++) {
281 loops
= atoi(&arg
[2]);
297 /* do first decode to get the PFX into "our" form */
299 CFDataRef cfdPfx
= CFDataCreate(NULL
, pfx
, pfxLen
);
302 printf(" ...initial decode\n");
304 ortn
= p12Import(cfdPfx
, pwd
, kcRef1
, &refArray
);
306 printf("Error on initial p12Import; aborting.\n");
310 /* reencode. At this point the PFXs will not be identical since
311 * everyone packages these up a little differently. */
312 CFDataRef refPfx
= NULL
;
314 printf(" ...first reencode\n");
316 ortn
= p12Export(refArray
, pwd
, &refPfx
);
318 printf("Error on initial p12Export; aborting.\n");
321 CFDataRef pfxToDecode
= refPfx
;
322 CFRetain(pfxToDecode
);
324 for(unsigned loop
=0; loop
<loops
; loop
++) {
326 printf("..loop %u\n", loop
);
328 CFArrayRef testArray
;
330 printf(" ...decode\n");
332 ortn
= p12Import(pfxToDecode
, pwd
, kcRef2
, &testArray
);
338 * Compare that decode to our original
340 if(compareDecodedArrays(refArray
, testArray
, quiet
)) {
344 /* now reencode, should get blob with same length but different
345 * data (because salt is random each time) */
346 CFDataRef newPfx
= NULL
;
348 printf(" ...reencode\n");
350 ortn
= p12Export(testArray
, pwd
, &newPfx
);
355 if(CFDataGetLength(refPfx
) != CFDataGetLength(newPfx
)) {
356 printf("***PFX length miscompare after reencode\n");
357 writeBlobs(refPfx
, newPfx
);
360 if(!memcmp(CFDataGetBytePtr(refPfx
), CFDataGetBytePtr(newPfx
),
361 CFDataGetLength(refPfx
))) {
362 printf("***Unexpected PFX data compare after reencode\n");
363 writeBlobs(refPfx
, newPfx
);
366 CFRelease(pfxToDecode
);
367 pfxToDecode
= newPfx
;
370 printf("Hit CR to continue: ");
374 /* delete everything we imported into kcRef2 */
375 CFIndex numItems
= CFArrayGetCount(testArray
);
376 for(CFIndex dex
=0; dex
<numItems
; dex
++) {
377 SecKeychainItemRef itemRef
=
378 (SecKeychainItemRef
)CFArrayGetValueAtIndex(refArray
, dex
);
379 ortn
= SecKeychainItemDelete(itemRef
);
381 cssmPerror("SecKeychainItemDelete", ortn
);
383 * keep going, but if we're looping this will result in a dup
384 * item error on the next import
388 CFRelease(testArray
);
391 printf("...p12Reencode complete\n");