aboutsummaryrefslogtreecommitdiffstats
path: root/sm/certpath.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/certpath.c')
-rw-r--r--sm/certpath.c122
1 files changed, 119 insertions, 3 deletions
diff --git a/sm/certpath.c b/sm/certpath.c
index e76ff6c2f..0dac59acf 100644
--- a/sm/certpath.c
+++ b/sm/certpath.c
@@ -84,6 +84,114 @@ allowed_ca (KsbaCert cert, int *pathlen)
return 0;
}
+
+static int
+check_cert_policy (KsbaCert cert)
+{
+ KsbaError err;
+ char *policies;
+ FILE *fp;
+ int any_critical;
+
+ err = ksba_cert_get_cert_policies (cert, &policies);
+ if (err == KSBA_No_Data)
+ return 0; /* no policy given */
+ if (err)
+ return map_ksba_err (err);
+
+ /* STRING is a line delimited list of certifiate policies as stored
+ in the certificate. The line itself is colon delimted where the
+ first field is the OID of the policy and the second field either
+ N or C for normal or critical extension */
+
+ /* The check is very minimal but won't give false positives */
+ any_critical = !!strstr (policies, ":C");
+
+ if (!opt.policy_file)
+ {
+ xfree (policies);
+ if (any_critical)
+ {
+ log_error ("critical marked policy without configured policies\n");
+ return GNUPG_No_Policy_Match;
+ }
+ return 0;
+ }
+
+ fp = fopen (opt.policy_file, "r");
+ if (!fp)
+ {
+ log_error ("failed to open `%s': %s\n",
+ opt.policy_file, strerror (errno));
+ xfree (policies);
+ return GNUPG_Configuration_Error;
+ }
+
+ for (;;)
+ {
+ int c;
+ char *p, line[256];
+ char *haystack, *allowed;
+
+ /* read line */
+ do
+ {
+ if (!fgets (line, DIM(line)-1, fp) )
+ {
+ xfree (policies);
+ if (feof (fp))
+ {
+ fclose (fp);
+ log_error (_("certificate policy not allowed\n"));
+ /* with no critical policies this is only a warning */
+ return any_critical? GNUPG_No_Policy_Match : 0;
+ }
+ fclose (fp);
+ return GNUPG_Read_Error;
+ }
+
+ if (!*line || line[strlen(line)-1] != '\n')
+ {
+ /* eat until end of line */
+ while ( (c=getc (fp)) != EOF && c != '\n')
+ ;
+ fclose (fp);
+ xfree (policies);
+ return *line? GNUPG_Line_Too_Long: GNUPG_Incomplete_Line;
+ }
+
+ /* Allow for empty lines and spaces */
+ for (p=line; spacep (p); p++)
+ ;
+ }
+ while (!*p || *p == '\n' || *p == '#');
+
+ /* parse line */
+ for (allowed=line; spacep (allowed); allowed++)
+ ;
+ p = strpbrk (allowed, " :\n");
+ if (!*p || p == allowed)
+ {
+ fclose (fp);
+ xfree (policies);
+ return GNUPG_Configuration_Error;
+ }
+ *p = 0; /* strip the rest of the line */
+ /* See whether we find ALLOWED (which is an OID) in POLICIES */
+ for (haystack=policies; (p=strstr (haystack, allowed)); haystack = p+1)
+ {
+ if ( !(p == policies || p[-1] == '\n') )
+ continue; /* does not match the begin of a line */
+ if (p[strlen (allowed)] != ':')
+ continue; /* the length does not match */
+ /* Yep - it does match so return okay */
+ fclose (fp);
+ xfree (policies);
+ return 0;
+ }
+ }
+}
+
/* Return the next certificate up in the chain starting at START.
Returns -1 when there are no more certificates. */
int
@@ -216,7 +324,14 @@ gpgsm_validate_path (KsbaCert cert)
rc = unknown_criticals (subject_cert);
if (rc)
goto leave;
-
+
+ if (!opt.no_policy_check)
+ {
+ rc = check_cert_policy (subject_cert);
+ if (rc)
+ goto leave;
+ }
+
if (!opt.no_crl_check)
{
rc = gpgsm_dirmngr_isvalid (subject_cert);
@@ -360,9 +475,10 @@ gpgsm_validate_path (KsbaCert cert)
issuer_cert = NULL;
}
+ if (opt.no_policy_check)
+ log_info ("policies not checked due to --disable-policy-checks option\n");
if (opt.no_crl_check)
- log_info ("CRL was not checked due to --no-crl-cechk option\n");
-
+ log_info ("CRLs not checked due to --disable-crl-checks option\n");
leave:
xfree (issuer);