Initial support for policy certificates.
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17250 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		
							
								
								
									
										158
									
								
								lib/hx509/cert.c
									
									
									
									
									
								
							
							
						
						
									
										158
									
								
								lib/hx509/cert.c
									
									
									
									
									
								
							| @@ -506,9 +506,10 @@ _hx509_check_key_usage(hx509_cert cert, unsigned flags, int req_present) | |||||||
|     return check_key_usage(_hx509_get_cert(cert), flags, req_present); |     return check_key_usage(_hx509_get_cert(cert), flags, req_present); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | enum certtype { POLICY_CERT, EE_CERT, CA_CERT }; | ||||||
|  |  | ||||||
| static int | static int | ||||||
| check_basic_constraints(const Certificate *cert, int ca, int depth) | check_basic_constraints(const Certificate *cert, enum certtype type, int depth) | ||||||
| { | { | ||||||
|     BasicConstraints bc; |     BasicConstraints bc; | ||||||
|     const Extension *e; |     const Extension *e; | ||||||
| @@ -519,19 +520,37 @@ check_basic_constraints(const Certificate *cert, int ca, int depth) | |||||||
| 	return 0; | 	return 0; | ||||||
|  |  | ||||||
|     e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i); |     e = find_extension(cert, oid_id_x509_ce_basicConstraints(), &i); | ||||||
|     if (e == NULL) |     if (e == NULL) { | ||||||
|  | 	switch(type) { | ||||||
|  | 	case POLICY_CERT: | ||||||
|  | 	case EE_CERT: | ||||||
|  | 	    return 0; | ||||||
|  | 	case CA_CERT: | ||||||
| 	    return HX509_EXTENSION_NOT_FOUND; | 	    return HX509_EXTENSION_NOT_FOUND; | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|      |      | ||||||
|     ret = decode_BasicConstraints(e->extnValue.data,  |     ret = decode_BasicConstraints(e->extnValue.data,  | ||||||
| 				  e->extnValue.length, &bc, | 				  e->extnValue.length, &bc, | ||||||
| 				  &size); | 				  &size); | ||||||
|     if (ret) |     if (ret) | ||||||
| 	return ret; | 	return ret; | ||||||
|     if (ca && (bc.cA == NULL || !*bc.cA)) |     switch(type) { | ||||||
|  |     case POLICY_CERT: | ||||||
|  | 	if (bc.cA != NULL && *bc.cA) | ||||||
|  | 	    ret = HX509_PARENT_IS_CA; | ||||||
|  | 	break; | ||||||
|  |     case EE_CERT: | ||||||
|  | 	ret = 0; | ||||||
|  | 	break; | ||||||
|  |     case CA_CERT: | ||||||
|  | 	if (bc.cA == NULL || !*bc.cA) | ||||||
| 	    ret = HX509_PARENT_NOT_CA; | 	    ret = HX509_PARENT_NOT_CA; | ||||||
|     if (bc.pathLenConstraint) | 	else if (bc.pathLenConstraint) | ||||||
| 	    if (depth - 1 > *bc.pathLenConstraint) | 	    if (depth - 1 > *bc.pathLenConstraint) | ||||||
| 		ret = HX509_CA_PATH_TOO_DEEP; | 		ret = HX509_CA_PATH_TOO_DEEP; | ||||||
|  | 	break; | ||||||
|  |     } | ||||||
|     free_BasicConstraints(&bc); |     free_BasicConstraints(&bc); | ||||||
|     return ret; |     return ret; | ||||||
| } | } | ||||||
| @@ -1164,6 +1183,32 @@ free_name_constraints(hx509_name_constraints *nc) | |||||||
|     free(nc->val); |     free(nc->val); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static int | ||||||
|  | policy_cert_p(const Certificate *cert, ProxyCertInfo *info) | ||||||
|  | { | ||||||
|  |     const Extension *e; | ||||||
|  |     size_t size; | ||||||
|  |     int ret, i = 0; | ||||||
|  |  | ||||||
|  |     memset(info, 0, sizeof(*info)); | ||||||
|  |  | ||||||
|  |     e = find_extension(cert, oid_id_pe_proxyCertInfo(), &i); | ||||||
|  |     if (e == NULL) | ||||||
|  | 	return 0; | ||||||
|  |  | ||||||
|  |     ret = decode_ProxyCertInfo(e->extnValue.data,  | ||||||
|  | 			       e->extnValue.length, info, | ||||||
|  | 			       &size); | ||||||
|  |     if (ret) | ||||||
|  | 	return ret; | ||||||
|  |     if (size != e->extnValue.length) { | ||||||
|  | 	free_ProxyCertInfo(info); | ||||||
|  | 	return HX509_EXTRA_DATA_AFTER_STRUCTURE; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
| int | int | ||||||
| hx509_verify_path(hx509_context context, | hx509_verify_path(hx509_context context, | ||||||
| 		  hx509_verify_ctx ctx, | 		  hx509_verify_ctx ctx, | ||||||
| @@ -1175,7 +1220,8 @@ hx509_verify_path(hx509_context context, | |||||||
| #if 0 | #if 0 | ||||||
|     const AlgorithmIdentifier *alg_id; |     const AlgorithmIdentifier *alg_id; | ||||||
| #endif | #endif | ||||||
|     int ret, i; |     int ret, i, policy_cert_depth; | ||||||
|  |     enum certtype type; | ||||||
|  |  | ||||||
|     ret = init_name_constraints(&nc); |     ret = init_name_constraints(&nc); | ||||||
|     if (ret)	 |     if (ret)	 | ||||||
| @@ -1200,6 +1246,78 @@ hx509_verify_path(hx509_context context, | |||||||
|     alg_id = path.val[path->len - 1]->data->tbsCertificate.signature; |     alg_id = path.val[path->len - 1]->data->tbsCertificate.signature; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |      * Check CA and policy certificate chain from the top of the | ||||||
|  |      * certificate chain. Also check certificate is valid with respect | ||||||
|  |      * to the current time. | ||||||
|  |      * | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     policy_cert_depth = 0; | ||||||
|  |  | ||||||
|  |     type = POLICY_CERT; /* XXX works for now */ | ||||||
|  |  | ||||||
|  |     for (i = 0; i < path.len; i++) { | ||||||
|  | 	Certificate *c; | ||||||
|  | 	time_t t; | ||||||
|  |  | ||||||
|  | 	c = _hx509_get_cert(path.val[i]); | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 	 * Lets do some basic check on issuer like | ||||||
|  | 	 * keyUsage.keyCertSign and basicConstraints.cA bit depending | ||||||
|  | 	 * on what type of certificate this is. | ||||||
|  | 	 */ | ||||||
|  |  | ||||||
|  | 	switch (type) { | ||||||
|  | 	case CA_CERT: | ||||||
|  | 	    ret = check_key_usage(c, 1 << 5, TRUE); /* XXX make constants */ | ||||||
|  | 	    if (ret) | ||||||
|  | 		goto out; | ||||||
|  | 	    break; | ||||||
|  | 	case POLICY_CERT: { | ||||||
|  | 	    ProxyCertInfo info;	     | ||||||
|  |  | ||||||
|  | 	    if (policy_cert_p(c, &info)) { | ||||||
|  |  | ||||||
|  | 		if (info.pCPathLenConstraint != NULL && | ||||||
|  | 		    *info.pCPathLenConstraint > i) | ||||||
|  | 		{ | ||||||
|  | 		    free_ProxyCertInfo(&info); | ||||||
|  | 		    ret = HX509_PATH_TOO_LONG; | ||||||
|  | 		    goto out; | ||||||
|  | 		} | ||||||
|  | 		free_ProxyCertInfo(&info); | ||||||
|  | 		break; | ||||||
|  | 	    } | ||||||
|  | 	    type = EE_CERT; | ||||||
|  | 	    /* FALLTHOUGH */ | ||||||
|  | 	} | ||||||
|  | 	case EE_CERT: | ||||||
|  | 	    break; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ret = check_basic_constraints(c, type, i - policy_cert_depth); | ||||||
|  | 	if (ret) | ||||||
|  | 	    goto out; | ||||||
|  |  | ||||||
|  | 	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); | ||||||
|  | 	if (t > ctx->time_now) { | ||||||
|  | 	    ret = HX509_CERT_USED_BEFORE_TIME; | ||||||
|  | 	    goto out; | ||||||
|  | 	} | ||||||
|  | 	t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); | ||||||
|  | 	if (t < ctx->time_now) { | ||||||
|  | 	    ret = HX509_CERT_USED_AFTER_TIME; | ||||||
|  | 	    goto out; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	if (type == EE_CERT) | ||||||
|  | 	    type = CA_CERT; | ||||||
|  | 	else if (type == POLICY_CERT) | ||||||
|  | 	    policy_cert_depth++; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /* |     /* | ||||||
|      * Verify constraints, do this backward so path constraints are |      * Verify constraints, do this backward so path constraints are | ||||||
|      * checked in the right order. |      * checked in the right order. | ||||||
| @@ -1220,36 +1338,6 @@ hx509_verify_path(hx509_context context, | |||||||
| 	} | 	} | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| 	/* |  | ||||||
| 	 * Lets do some basic check on issuer like |  | ||||||
| 	 * keyUsage.keyCertSign and basicConstraints.cA bit. |  | ||||||
| 	 */ |  | ||||||
| 	if (i != 0) { |  | ||||||
| 	    if (check_key_usage(c, 1 << 5, TRUE)) { /* XXX make constants */ |  | ||||||
| 		ret = ENOENT; |  | ||||||
| 		goto out; |  | ||||||
| 	    } |  | ||||||
| 	    if (check_basic_constraints(c, 1, path.len - i - 1)) { |  | ||||||
| 		ret = ENOENT; |  | ||||||
| 		goto out; |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	{ |  | ||||||
| 	    time_t t; |  | ||||||
|  |  | ||||||
| 	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notBefore); |  | ||||||
| 	    if (t > ctx->time_now) { |  | ||||||
| 		ret = HX509_CERT_USED_BEFORE_TIME; |  | ||||||
| 		goto out; |  | ||||||
| 	    } |  | ||||||
| 	    t = _hx509_Time2time_t(&c->tbsCertificate.validity.notAfter); |  | ||||||
| 	    if (t < ctx->time_now) { |  | ||||||
| 		ret = HX509_CERT_USED_AFTER_TIME; |  | ||||||
| 		goto out; |  | ||||||
| 	    } |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	/* verify name constraints, not for selfsigned and anchor */ | 	/* verify name constraints, not for selfsigned and anchor */ | ||||||
| 	if (!certificate_is_self_signed(c) || i == path.len - 1) { | 	if (!certificate_is_self_signed(c) || i == path.len - 1) { | ||||||
| 	    ret = check_name_constraints(&nc, c); | 	    ret = check_name_constraints(&nc, c); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Love Hörnquist Åstrand
					Love Hörnquist Åstrand