1 /* $OpenBSD: validate.c,v 1.10 2019/11/29 05:16:54 benno Exp $ */ 2 /* 3 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/socket.h> 19 20 #include <arpa/inet.h> 21 #include <assert.h> 22 #include <err.h> 23 #include <inttypes.h> 24 #include <stdarg.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include <openssl/ssl.h> 30 31 #include "extern.h" 32 33 static void 34 tracewarn(const struct auth *a) 35 { 36 37 for (; a != NULL; a = a->parent) 38 warnx(" ...inheriting from: %s", a->fn); 39 } 40 41 /* 42 * Walk up the chain of certificates trying to match our AS number to 43 * one of the allocations in that chain. 44 * Returns 1 if covered or 0 if not. 45 */ 46 static int 47 valid_as(struct auth *a, uint32_t min, uint32_t max) 48 { 49 int c; 50 51 if (a == NULL) 52 return 0; 53 54 /* Does this certificate cover our AS number? */ 55 if (a->cert->asz) { 56 c = as_check_covered(min, max, 57 a->cert->as, a->cert->asz); 58 if (c > 0) 59 return 1; 60 else if (c < 0) 61 return 0; 62 } 63 64 /* If it doesn't, walk up the chain. */ 65 return valid_as(a->parent, min, max); 66 } 67 68 /* 69 * Walk up the chain of certificates (really just the last one, but in 70 * the case of inheritence, the ones before) making sure that our IP 71 * prefix is covered in the first non-inheriting specification. 72 * Returns 1 if covered or 0 if not. 73 */ 74 static int 75 valid_ip(struct auth *a, enum afi afi, 76 const unsigned char *min, const unsigned char *max) 77 { 78 int c; 79 80 if (a == NULL) 81 return 0; 82 83 /* Does this certificate cover our IP prefix? */ 84 c = ip_addr_check_covered(afi, min, max, 85 a->cert->ips, a->cert->ipsz); 86 if (c > 0) 87 return 1; 88 else if (c < 0) 89 return 0; 90 91 /* If it doesn't, walk up the chain. */ 92 return valid_ip(a->parent, afi, min, max); 93 } 94 95 /* 96 * Make sure that the SKI doesn't already exist and return the parent by 97 * its AKI. 98 * Returns the parent auth or NULL on failure. 99 */ 100 struct auth * 101 valid_ski_aki(const char *fn, struct auth_tree *auths, 102 const char *ski, const char *aki) 103 { 104 struct auth *a; 105 106 if (auth_find(auths, ski) != NULL) { 107 warnx("%s: RFC 6487: duplicate SKI", fn); 108 return NULL; 109 } 110 111 a = auth_find(auths, aki); 112 if (a == NULL) 113 warnx("%s: RFC 6487: unknown AKI", fn); 114 115 return a; 116 } 117 118 /* 119 * Authenticate a trust anchor by making sure its resources are not 120 * inheriting and that the SKI is unique. 121 * Returns 1 if valid, 0 otherwise. 122 */ 123 int 124 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert) 125 { 126 size_t i; 127 128 /* AS and IP resources must not inherit. */ 129 if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) { 130 warnx("%s: RFC 6487 (trust anchor): " 131 "inheriting AS resources", fn); 132 return 0; 133 } 134 for (i = 0; i < cert->ipsz; i++) 135 if (cert->ips[i].type == CERT_IP_INHERIT) { 136 warnx("%s: RFC 6487 (trust anchor): " 137 "inheriting IP resources", fn); 138 return 0; 139 } 140 141 /* SKI must not be a dupe. */ 142 if (auth_find(auths, cert->ski) != NULL) { 143 warnx("%s: RFC 6487: duplicate SKI", fn); 144 return 0; 145 } 146 147 return 1; 148 } 149 150 /* 151 * Validate a non-TA certificate: make sure its IP and AS resources are 152 * fully covered by those in the authority key (which must exist). 153 * Returns 1 if valid, 0 otherwise. 154 */ 155 int 156 valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert) 157 { 158 struct auth *a; 159 size_t i; 160 uint32_t min, max; 161 char buf1[64], buf2[64]; 162 163 a = valid_ski_aki(fn, auths, cert->ski, cert->aki); 164 if (a == NULL) 165 return 0; 166 167 for (i = 0; i < cert->asz; i++) { 168 if (cert->as[i].type == CERT_AS_INHERIT) 169 continue; 170 min = cert->as[i].type == CERT_AS_ID ? 171 cert->as[i].id : cert->as[i].range.min; 172 max = cert->as[i].type == CERT_AS_ID ? 173 cert->as[i].id : cert->as[i].range.max; 174 if (valid_as(a, min, max)) 175 continue; 176 warnx("%s: RFC 6487: uncovered AS: " 177 "%u--%u", fn, min, max); 178 tracewarn(a); 179 return 0; 180 } 181 182 for (i = 0; i < cert->ipsz; i++) { 183 if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, 184 cert->ips[i].max)) 185 continue; 186 switch (cert->ips[i].type) { 187 case CERT_IP_RANGE: 188 ip_addr_print(&cert->ips[i].range.min, 189 cert->ips[i].afi, buf1, sizeof(buf1)); 190 ip_addr_print(&cert->ips[i].range.max, 191 cert->ips[i].afi, buf2, sizeof(buf2)); 192 warnx("%s: RFC 6487: uncovered IP: " 193 "%s--%s", fn, buf1, buf2); 194 break; 195 case CERT_IP_ADDR: 196 ip_addr_print(&cert->ips[i].ip, 197 cert->ips[i].afi, buf1, sizeof(buf1)); 198 warnx("%s: RFC 6487: uncovered IP: " 199 "%s", fn, buf1); 200 case CERT_IP_INHERIT: 201 warnx("%s: RFC 6487: uncovered IP: " 202 "(inherit)", fn); 203 break; 204 } 205 tracewarn(a); 206 return 0; 207 } 208 209 return 1; 210 } 211 212 /* 213 * Validate our ROA: check that the SKI is unique, the AKI exists, and 214 * the IP prefix is also contained. 215 * Returns 1 if valid, 0 otherwise. 216 */ 217 int 218 valid_roa(const char *fn, struct auth_tree *auths, struct roa *roa) 219 { 220 struct auth *a; 221 size_t i; 222 char buf[64]; 223 224 a = valid_ski_aki(fn, auths, roa->ski, roa->aki); 225 if (a == NULL) 226 return 0; 227 228 if ((roa->tal = strdup(a->tal)) == NULL) 229 err(1, NULL); 230 231 for (i = 0; i < roa->ipsz; i++) { 232 if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min, 233 roa->ips[i].max)) 234 continue; 235 ip_addr_print(&roa->ips[i].addr, 236 roa->ips[i].afi, buf, sizeof(buf)); 237 warnx("%s: RFC 6482: uncovered IP: " 238 "%s", fn, buf); 239 tracewarn(a); 240 return 0; 241 } 242 243 return 1; 244 } 245