2 * script.cpp - run certcrl from script file
5 #include <security_cdsa_utils/cuFileIo.h>
6 #include <utilLib/common.h>
11 #include <Security/cssm.h>
12 #include <clAppUtils/BlobList.h>
13 #include <clAppUtils/certVerify.h>
16 /* Line type returned from parseLine */
18 LT_Empty
, // comments, whitespace
26 LT_ExpectError
, // expected function return
27 LT_CertError
, // per-cert error string
28 LT_CertStatus
, // per-cert StatusBits
48 /* variables which can be in globals or per-test */
51 LT_CertNetFetchEnable
,
56 LT_OcspNetFetchDisable
,
57 LT_RequireOcspIfPresent
,
58 LT_RequireCrlIfPresent
,
63 /* table to map key names to LineType */
69 KeyLineType keyLineTypes
[] =
71 { "test", LT_TestName
},
72 { "dir", LT_DirName
},
76 { "certDb", LT_CertDb
},
77 { "crlDb", LT_CrlDb
}, // no longer used
78 { "error", LT_ExpectError
},
79 { "certerror", LT_CertError
},
80 { "certstatus", LT_CertStatus
},
81 { "sslHost", LT_SslHost
},
82 { "sslClient", LT_SslClient
},
83 { "senderEmail", LT_SenderEmail
},
84 { "policy", LT_Policy
},
85 { "keyUsage", LT_KeyUsage
},
86 { "revokePolicy", LT_RevokePolicy
},
87 { "responderURI", LT_RespURI
},
88 { "responderCert", LT_RespCert
},
89 { "cacheDisable", LT_CacheDisable
},
91 { "globals", LT_Globals
},
92 { "end", LT_EndOfSection
},
93 { "allowUnverified", LT_AllowUnverified
},
94 { "requireCrlIfPresent",LT_RequireCrlIfPresent
},
95 { "crlNetFetchEnable", LT_CrlNetFetchEnable
},
96 { "certNetFetchEnable", LT_CertNetFetchEnable
},
97 { "ocspNetFetchDisable",LT_OcspNetFetchDisable
},
98 { "requireCrlForAll", LT_RequireCrlForAll
},
99 { "requireOcspForAll", LT_RequireOcspForAll
},
100 { "useSystemAnchors", LT_UseSystemAnchors
},
101 { "useTrustSettings", LT_UseTrustSettings
},
102 { "leafCertIsCA", LT_LeafCertIsCA
},
103 { "requireOcspIfPresent",LT_RequireOcspIfPresent
},
104 { "generateOcspNonce", LT_GenerateOcspNonce
},
105 { "requireOcspNonce", LT_RequireOcspNonce
},
106 { "allowExpiredRoot", LT_AllowExpiredRoot
},
107 { "verifyTime", LT_VerifyTime
},
108 { "implicitAnchors", LT_ImplicitAnchors
},
111 #define NUM_KEYS (sizeof(keyLineTypes) / sizeof(KeyLineType))
113 /* map policy string to CertVerifyPolicy */
116 CertVerifyPolicy policy
;
119 static const PolicyString policyStrings
[] =
121 { "basic", CVP_Basic
},
123 { "smime", CVP_SMIME
},
124 { "swuSign", CVP_SWUpdateSign
},
125 { "codeSign", CVP_AppleCodeSigning
},
126 { "pkgSign", CVP_PackageSigning
},
127 { "resourceSign", CVP_ResourceSigning
},
128 { "iChat", CVP_iChat
},
129 { "pkinitServer", CVP_PKINIT_Server
},
130 { "pkinitClient", CVP_PKINIT_Client
},
131 { "IPSec", CVP_IPSec
},
132 { NULL
, (CertVerifyPolicy
)0 }
135 /* skip whitespace (but not line terminators) */
136 static void skipWhite(
137 const unsigned char *&cp
,
140 while(bytesLeft
!= 0) {
153 /* skip to next char after EOL */
154 static void skipLine(
155 const unsigned char *&cp
,
158 bool foundEol
= false;
159 while(bytesLeft
!= 0) {
178 /* skip to end of current token (i.e., find next whitespace or '=') */
179 static void skipToken(
180 const unsigned char *&cp
,
184 while(bytesLeft
!= 0) {
188 /* end of quoted string, return still pointing to it */
197 /* hopefully, end of key */
207 * Parse one line, return value (following "=" and whitespace) as
208 * mallocd C string. On return, scriptData points to next char after line
211 * The basic form of a line is
212 * [whitespace] key [whitespace] = [whitespace] value [whitespace] \n|\r...
214 * ...except for comments and blank lines. Comments contain '#' as the
215 * first non-whitespace char.
217 #define CHECK_EOF(bytesLeft) \
218 if(bytesLeft == 0) { \
222 #define MAX_KEY_LEN 80
224 static LineType
parseLine(
225 const unsigned char *&cp
, // IN/OUT
226 unsigned &bytesLeft
, // IN/OUT bytes left in script
227 char *&value
, // mallocd and RETURNED
232 printf("...EOF reached\n");
236 skipWhite(cp
, bytesLeft
);
244 skipLine(cp
, bytesLeft
);
249 * cp points to start of key
250 * get key value as NULL terminated C string
252 const unsigned char *tokenStart
= cp
;
253 skipToken(cp
, bytesLeft
, false);
254 CHECK_EOF(bytesLeft
);
255 unsigned tokenLen
= cp
- tokenStart
;
256 char key
[MAX_KEY_LEN
];
257 memmove(key
, tokenStart
, tokenLen
);
258 key
[tokenLen
] = '\0';
261 LineType rtnType
= LT_BadLine
;
262 for(unsigned i
=0; i
<NUM_KEYS
; i
++) {
263 KeyLineType
*klt
= &keyLineTypes
[i
];
264 if(!strcmp(klt
->keyName
, key
)) {
265 rtnType
= klt
->lineType
;
270 /* these keys have no value */
271 bool noValue
= false;
273 case LT_EndOfSection
:
275 printf("...end of section\n");
283 printf("***unknown key '%s'\n", key
);
291 skipLine(cp
, bytesLeft
);
295 /* get to start of value */
296 skipWhite(cp
, bytesLeft
);
297 CHECK_EOF(bytesLeft
);
298 if(rtnType
== LT_Echo
) {
299 /* echo: value is everything from this char to end of line */
301 for( ; bytesLeft
!= 0; cp
++, bytesLeft
--) {
302 if((*cp
== '\n') || (*cp
== '\r')) {
306 if(cp
!= tokenStart
) {
307 tokenLen
= cp
- tokenStart
;
308 value
= (char *)malloc(tokenLen
+ 1);
309 memmove(value
, tokenStart
, tokenLen
);
310 value
[tokenLen
] = '\0';
315 skipLine(cp
, bytesLeft
);
319 /* all other line types: value is first token after '=' */
321 printf("===missing = after key\n");
326 skipWhite(cp
, bytesLeft
);
327 CHECK_EOF(bytesLeft
);
329 /* cp points to start of value */
330 bool isQuoted
= false;
338 skipToken(cp
, bytesLeft
, isQuoted
);
339 /* cp points to next char after end of value */
340 /* get value as mallocd C string */
341 tokenLen
= cp
- tokenStart
;
346 value
= (char *)malloc(tokenLen
+ 1);
347 memmove(value
, tokenStart
, tokenLen
);
348 value
[tokenLen
] = '\0';
350 skipLine(cp
, bytesLeft
);
352 printf("'%s' = '%s'\n", key
, value
);
357 /* describe fate of one run of runOneTest() */
364 /* parse boolean variable, in globals or per-test */
365 OneTestResult
parseVar(
368 ScriptVars
&scriptVars
)
372 if(!strcmp(value
, "true")) {
375 else if(!strcmp(value
, "false")) {
379 printf("***boolean variables must be true or false, not '%s'\n", value
);
384 case LT_AllowUnverified
:
385 scriptVars
.allowUnverified
= cval
;
387 case LT_CrlNetFetchEnable
:
388 scriptVars
.crlNetFetchEnable
= cval
;
390 case LT_CertNetFetchEnable
:
391 scriptVars
.certNetFetchEnable
= cval
;
393 case LT_UseSystemAnchors
:
394 scriptVars
.useSystemAnchors
= cval
;
396 case LT_UseTrustSettings
:
397 scriptVars
.useTrustSettings
= cval
;
399 case LT_LeafCertIsCA
:
400 scriptVars
.leafCertIsCA
= cval
;
402 case LT_CacheDisable
:
403 scriptVars
.cacheDisable
= cval
;
405 case LT_OcspNetFetchDisable
:
406 scriptVars
.ocspNetFetchDisable
= cval
;
408 case LT_RequireOcspIfPresent
:
409 scriptVars
.requireOcspIfPresent
= cval
;
411 case LT_RequireCrlIfPresent
:
412 scriptVars
.requireCrlIfPresent
= cval
;
414 case LT_RequireCrlForAll
:
415 scriptVars
.requireCrlForAll
= cval
;
417 case LT_RequireOcspForAll
:
418 scriptVars
.requireOcspForAll
= cval
;
427 /* sure wish X had strnstr */
428 static char *strnstr(
434 unsigned littleLen
= strlen(little
);
435 const char *end
= big
+ len
- littleLen
;
436 char first
= little
[0];
438 for(cp
=big
; cp
<end
; cp
++) {
439 /* find first char of little in what's left of big */
443 if(memcmp(cp
, little
, littleLen
) == 0) {
451 OneTestResult
fetchGlobals(
452 const unsigned char *&scriptData
, // IN/OUT
453 unsigned &bytesLeft
, // IN/OUT
454 ScriptVars
&scriptVars
, // may be modified
457 char *value
; // mallocd by parseLine
459 OneTestResult result
;
462 printf("...processing global section\n");
464 /* parse globals section until end encountered */
467 lineType
= parseLine(scriptData
, bytesLeft
, value
, verbose
);
472 case LT_EndOfSection
:
475 printf("***Premature end of file in globals section.\n");
476 return OTR_EndOfScript
;
480 /* hopefully a variable */
481 result
= parseVar(lineType
, value
, scriptVars
);
482 if(result
!= OTR_Success
) {
495 /* parse script fragment for one test, run it */
496 OneTestResult
runOneTest(
497 const unsigned char *&scriptData
, // IN/OUT
498 unsigned &bytesLeft
, // IN/OUT bytes left in script
499 CSSM_TP_HANDLE tpHand
,
500 CSSM_CL_HANDLE clHand
,
501 CSSM_CSP_HANDLE cspHand
,
502 CSSM_DL_HANDLE dlHand
,
503 ScriptVars
&scriptVars
,
507 CertVerifyArgs vfyArgs
;
508 memset(&vfyArgs
, 0, sizeof(vfyArgs
));
510 /* to be gathered from script */
511 char *testName
= NULL
;
512 char *dirName
= NULL
;
518 char *value
; // mallocd by parseLine
520 ScriptVars localVars
= scriptVars
;
521 OneTestResult result
;
524 CSSM_DL_DB_HANDLE_PTR currDlDb
= NULL
;
525 CSSM_DL_DB_LIST dlDbList
= {0, NULL
};
527 vfyArgs
.version
= CERT_VFY_ARGS_VERS
;
528 vfyArgs
.certs
= &certs
;
529 vfyArgs
.roots
= &roots
;
530 vfyArgs
.crls
= &crls
;
531 vfyArgs
.quiet
= quiet
;
532 vfyArgs
.tpHand
= tpHand
;
533 vfyArgs
.clHand
= clHand
;
534 vfyArgs
.cspHand
= cspHand
;
535 vfyArgs
.quiet
= quiet
;
536 vfyArgs
.revokePolicy
= CRP_None
;
537 vfyArgs
.vfyPolicy
= CVP_Basic
;
538 vfyArgs
.dlDbList
= &dlDbList
;
540 /* parse script up to end of test */
544 lineType
= parseLine(scriptData
, bytesLeft
, value
, verbose
);
549 if(testName
!= NULL
) {
550 printf("***Duplicate test name ignored\n");
554 testName
= value
; // free after test
559 if(dirName
!= NULL
) {
560 printf("***Duplicate directory name ignored\n");
564 dirName
= value
; // free after test
569 blobErr
= certs
.addFile(value
, dirName
);
572 blobErr
= roots
.addFile(value
, dirName
);
575 blobErr
= crls
.addFile(value
, dirName
);
579 /* these can be called multiple times */
581 sprintf(pathName
, "%s/%s", dirName
, value
);
584 strcpy(pathName
, value
);
586 dlDbList
.NumHandles
++;
587 dlDbList
.DLDBHandle
= (CSSM_DL_DB_HANDLE_PTR
)realloc(
589 dlDbList
.NumHandles
* sizeof(CSSM_DL_DB_HANDLE
));
590 currDlDb
= &dlDbList
.DLDBHandle
[dlDbList
.NumHandles
-1];
591 currDlDb
->DLHandle
= dlHand
;
592 crtn
= CSSM_DL_DbOpen(dlHand
,
595 CSSM_DB_ACCESS_READ
| CSSM_DB_ACCESS_WRITE
,
596 NULL
, // CSSM_ACCESS_CREDENTIALS *AccessCred
597 NULL
, // void *OpenParameters
598 &currDlDb
->DBHandle
);
600 printError("CSSM_DL_DbOpen", crtn
);
601 printf("***Error opening DB %s. Aborting.\n", value
);
606 if(vfyArgs
.expectedErrStr
!= NULL
) {
607 printf("***Duplicate expected error ignored\n");
611 vfyArgs
.expectedErrStr
= value
; // free after test
616 vfyArgs
.numCertErrors
++;
617 vfyArgs
.certErrors
= (const char **)realloc(vfyArgs
.certErrors
,
618 vfyArgs
.numCertErrors
* sizeof(char *));
619 vfyArgs
.certErrors
[vfyArgs
.numCertErrors
- 1] = value
;
620 value
= NULL
; // free after test
623 vfyArgs
.numCertStatus
++;
624 vfyArgs
.certStatus
= (const char **)realloc(vfyArgs
.certStatus
,
625 vfyArgs
.numCertStatus
* sizeof(char *));
626 vfyArgs
.certStatus
[vfyArgs
.numCertStatus
- 1] = value
;
627 value
= NULL
; // // free after test
630 vfyArgs
.sslHost
= value
;
631 value
= NULL
; // free after test
632 vfyArgs
.vfyPolicy
= CVP_SSL
;
635 vfyArgs
.senderEmail
= value
;
636 value
= NULL
; // free after test
637 if(vfyArgs
.vfyPolicy
== CVP_Basic
) {
638 /* don't overwrite if it's already been set to e.g. iChat */
639 vfyArgs
.vfyPolicy
= CVP_SMIME
;
643 if(parsePolicyString(value
, &vfyArgs
.vfyPolicy
)) {
644 printf("Bogus policyValue (%s)\n", value
);
645 printPolicyStrings();
650 vfyArgs
.intendedKeyUse
= hexToBin(value
);
652 case LT_RevokePolicy
:
653 if(!strcmp(value
, "none")) {
654 vfyArgs
.revokePolicy
= CRP_None
;
656 else if(!strcmp(value
, "crl")) {
657 vfyArgs
.revokePolicy
= CRP_CRL
;
659 else if(!strcmp(value
, "ocsp")) {
660 vfyArgs
.revokePolicy
= CRP_OCSP
;
662 else if(!strcmp(value
, "both")) {
663 vfyArgs
.revokePolicy
= CRP_CRL_OCSP
;
666 printf("***Illegal revokePolicy (%s)\n.", value
);
671 vfyArgs
.responderURI
= value
;
672 value
= NULL
; // free after test
675 vfyArgs
.vfyTime
= value
;
676 value
= NULL
; // free after test
679 if(readFile(value
, (unsigned char **)&vfyArgs
.responderCert
,
680 &vfyArgs
.responderCertLen
)) {
681 printf("***Error reading responderCert from %s\n", value
);
685 case LT_EndOfSection
:
688 /* only legal if we haven't gotten a test name */
689 if(testName
== NULL
) {
690 return OTR_EndOfScript
;
692 printf("***Premature end of file.\n");
697 result
= fetchGlobals(scriptData
, bytesLeft
, scriptVars
, verbose
);
698 if(result
!= OTR_Success
) {
699 printf("***Bad globals section\n");
702 /* and start over with these variables */
703 localVars
= scriptVars
;
706 if(!strcmp(value
, "true")) {
707 vfyArgs
.sslClient
= CSSM_TRUE
;
710 vfyArgs
.sslClient
= CSSM_FALSE
;
712 vfyArgs
.vfyPolicy
= CVP_SSL
;
716 printf("%s\n", value
);
719 case LT_GenerateOcspNonce
:
720 vfyArgs
.generateOcspNonce
= CSSM_TRUE
;
722 case LT_RequireOcspNonce
:
723 vfyArgs
.requireOcspRespNonce
= CSSM_TRUE
;
725 case LT_AllowExpiredRoot
:
726 if(!strcmp(value
, "true")) {
727 vfyArgs
.allowExpiredRoot
= CSSM_TRUE
;
730 vfyArgs
.allowExpiredRoot
= CSSM_FALSE
;
733 case LT_ImplicitAnchors
:
734 if(!strcmp(value
, "true")) {
735 vfyArgs
.implicitAnchors
= CSSM_TRUE
;
738 vfyArgs
.implicitAnchors
= CSSM_FALSE
;
742 /* hopefully a variable */
743 result
= parseVar(lineType
, value
, localVars
);
744 if(result
!= OTR_Success
) {
745 printf("**Bogus line in script %u bytes from EOF\n",
758 } while(lineType
!= LT_EndOfSection
);
760 /* some args: copy from ScriptVars -> CertVerifyArgs */
761 vfyArgs
.allowUnverified
= localVars
.allowUnverified
;
762 vfyArgs
.requireOcspIfPresent
= localVars
.requireOcspIfPresent
;
763 vfyArgs
.requireCrlIfPresent
= localVars
.requireCrlIfPresent
;
764 vfyArgs
.crlNetFetchEnable
= localVars
.crlNetFetchEnable
;
765 vfyArgs
.certNetFetchEnable
= localVars
.certNetFetchEnable
;
766 vfyArgs
.useSystemAnchors
= localVars
.useSystemAnchors
;
767 vfyArgs
.useTrustSettings
= localVars
.useTrustSettings
;
768 vfyArgs
.leafCertIsCA
= localVars
.leafCertIsCA
;
769 vfyArgs
.disableCache
= localVars
.cacheDisable
;
770 vfyArgs
.disableOcspNet
= localVars
.ocspNetFetchDisable
;
771 vfyArgs
.requireCrlForAll
= localVars
.requireCrlForAll
;
772 vfyArgs
.requireOcspForAll
= localVars
.requireOcspForAll
;
773 vfyArgs
.verbose
= verbose
;
776 if(!quiet
&& (testName
!= NULL
)) {
777 printf("%s\n", testName
);
779 int rtn
= certVerify(&vfyArgs
);
781 OneTestResult ourRtn
= OTR_Success
;
783 printf("***Failure on %s\n", testName
);
784 if(testError(quiet
)) {
788 /* free the stuff that didn't get freed and the end of the
789 * main per-line loop */
790 if(dirName
!= NULL
) {
793 if(vfyArgs
.expectedErrStr
!= NULL
) {
794 free((void *)vfyArgs
.expectedErrStr
);
796 if(vfyArgs
.certErrors
!= NULL
) {
797 for(unsigned i
=0; i
<vfyArgs
.numCertErrors
; i
++) {
798 free((void *)vfyArgs
.certErrors
[i
]); // mallocd by parseLine
800 free((void *)vfyArgs
.certErrors
); // reallocd by us
802 if(vfyArgs
.certStatus
!= NULL
) {
803 for(unsigned i
=0; i
<vfyArgs
.numCertStatus
; i
++) {
804 free((void *)vfyArgs
.certStatus
[i
]); // mallocd by parseLine
806 free((void *)vfyArgs
.certStatus
); // reallocd by us
808 if(testName
!= NULL
) {
811 if(vfyArgs
.sslHost
) {
812 free((void *)vfyArgs
.sslHost
);
814 if(vfyArgs
.senderEmail
) {
815 free((void *)vfyArgs
.senderEmail
);
817 if(vfyArgs
.responderURI
) {
818 free((void *)vfyArgs
.responderURI
);
820 if(vfyArgs
.responderCert
) {
821 free((void *)vfyArgs
.responderCert
);
823 if(vfyArgs
.vfyTime
) {
824 free((void *)vfyArgs
.vfyTime
);
826 if(dlDbList
.DLDBHandle
) {
827 for(unsigned dex
=0; dex
<dlDbList
.NumHandles
; dex
++) {
828 CSSM_DL_DbClose(dlDbList
.DLDBHandle
[dex
]);
830 free(dlDbList
.DLDBHandle
);
836 const char *fileName
,
837 CSSM_TP_HANDLE tpHand
,
838 CSSM_CL_HANDLE clHand
,
839 CSSM_CSP_HANDLE cspHand
,
840 CSSM_DL_HANDLE dlHand
,
841 ScriptVars
*scriptVars
,
846 const unsigned char *scriptData
;
848 unsigned scriptDataLen
;
850 ScriptVars localVars
= *scriptVars
;
852 rtn
= readFile(fileName
, &cp
, &scriptDataLen
);
854 printf("***Error reading script file; aborting.\n");
855 printf("***Are you sure you're running this from the proper directory?\n");
858 scriptData
= (const unsigned char *)cp
;
859 OneTestResult result
;
862 result
= runOneTest(scriptData
, scriptDataLen
,
863 tpHand
, clHand
, cspHand
, dlHand
,
864 localVars
, quiet
, verbose
);
865 if(result
== OTR_Fail
) {
871 printf("CR to continue: ");
874 } while(result
== OTR_Success
);
879 /* parse policy string; returns nonzero if not found */
880 int parsePolicyString(
882 CertVerifyPolicy
*policy
)
884 const PolicyString
*ps
;
885 for(ps
=policyStrings
; ps
->str
; ps
++) {
886 if(!strcmp(ps
->str
, str
)) {
887 *policy
= ps
->policy
;
894 void printPolicyStrings()
896 printf("Valid policy strings are:\n ");
897 const PolicyString
*ps
;
899 for(ps
=policyStrings
; ps
->str
; ps
++, i
++) {
900 printf("%s", ps
->str
);
901 if(ps
[1].str
== NULL
) {
914 void printScriptVars()
916 printf("The list of script variables is as follows:\n");
917 for(unsigned dex
=0; dex
<NUM_KEYS
; dex
++) {
918 printf(" %s\n", keyLineTypes
[dex
].keyName
);
920 printPolicyStrings();
921 printf("Valid revokePolicy strings are:\n none, crl, ocsp, both\n");