1 /* $OpenBSD: validate.c,v 1.11 2020/09/12 15:46:48 claudio 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 "extern.h" 30 31 static void 32 tracewarn(const struct auth *a) 33 { 34 35 for (; a != NULL; a = a->parent) 36 warnx(" ...inheriting from: %s", a->fn); 37 } 38 39 /* 40 * Walk up the chain of certificates trying to match our AS number to 41 * one of the allocations in that chain. 42 * Returns 1 if covered or 0 if not. 43 */ 44 static int 45 valid_as(struct auth *a, uint32_t min, uint32_t max) 46 { 47 int c; 48 49 if (a == NULL) 50 return 0; 51 52 /* Does this certificate cover our AS number? */ 53 if (a->cert->asz) { 54 c = as_check_covered(min, max, 55 a->cert->as, a->cert->asz); 56 if (c > 0) 57 return 1; 58 else if (c < 0) 59 return 0; 60 } 61 62 /* If it doesn't, walk up the chain. */ 63 return valid_as(a->parent, min, max); 64 } 65 66 /* 67 * Walk up the chain of certificates (really just the last one, but in 68 * the case of inheritence, the ones before) making sure that our IP 69 * prefix is covered in the first non-inheriting specification. 70 * Returns 1 if covered or 0 if not. 71 */ 72 static int 73 valid_ip(struct auth *a, enum afi afi, 74 const unsigned char *min, const unsigned char *max) 75 { 76 int c; 77 78 if (a == NULL) 79 return 0; 80 81 /* Does this certificate cover our IP prefix? */ 82 c = ip_addr_check_covered(afi, min, max, 83 a->cert->ips, a->cert->ipsz); 84 if (c > 0) 85 return 1; 86 else if (c < 0) 87 return 0; 88 89 /* If it doesn't, walk up the chain. */ 90 return valid_ip(a->parent, afi, min, max); 91 } 92 93 /* 94 * Make sure that the SKI doesn't already exist and return the parent by 95 * its AKI. 96 * Returns the parent auth or NULL on failure. 97 */ 98 struct auth * 99 valid_ski_aki(const char *fn, struct auth_tree *auths, 100 const char *ski, const char *aki) 101 { 102 struct auth *a; 103 104 if (auth_find(auths, ski) != NULL) { 105 warnx("%s: RFC 6487: duplicate SKI", fn); 106 return NULL; 107 } 108 109 a = auth_find(auths, aki); 110 if (a == NULL) 111 warnx("%s: RFC 6487: unknown AKI", fn); 112 113 return a; 114 } 115 116 /* 117 * Authenticate a trust anchor by making sure its resources are not 118 * inheriting and that the SKI is unique. 119 * Returns 1 if valid, 0 otherwise. 120 */ 121 int 122 valid_ta(const char *fn, struct auth_tree *auths, const struct cert *cert) 123 { 124 size_t i; 125 126 /* AS and IP resources must not inherit. */ 127 if (cert->asz && cert->as[0].type == CERT_AS_INHERIT) { 128 warnx("%s: RFC 6487 (trust anchor): " 129 "inheriting AS resources", fn); 130 return 0; 131 } 132 for (i = 0; i < cert->ipsz; i++) 133 if (cert->ips[i].type == CERT_IP_INHERIT) { 134 warnx("%s: RFC 6487 (trust anchor): " 135 "inheriting IP resources", fn); 136 return 0; 137 } 138 139 /* SKI must not be a dupe. */ 140 if (auth_find(auths, cert->ski) != NULL) { 141 warnx("%s: RFC 6487: duplicate SKI", fn); 142 return 0; 143 } 144 145 return 1; 146 } 147 148 /* 149 * Validate a non-TA certificate: make sure its IP and AS resources are 150 * fully covered by those in the authority key (which must exist). 151 * Returns 1 if valid, 0 otherwise. 152 */ 153 int 154 valid_cert(const char *fn, struct auth_tree *auths, const struct cert *cert) 155 { 156 struct auth *a; 157 size_t i; 158 uint32_t min, max; 159 char buf1[64], buf2[64]; 160 161 a = valid_ski_aki(fn, auths, cert->ski, cert->aki); 162 if (a == NULL) 163 return 0; 164 165 for (i = 0; i < cert->asz; i++) { 166 if (cert->as[i].type == CERT_AS_INHERIT) 167 continue; 168 min = cert->as[i].type == CERT_AS_ID ? 169 cert->as[i].id : cert->as[i].range.min; 170 max = cert->as[i].type == CERT_AS_ID ? 171 cert->as[i].id : cert->as[i].range.max; 172 if (valid_as(a, min, max)) 173 continue; 174 warnx("%s: RFC 6487: uncovered AS: " 175 "%u--%u", fn, min, max); 176 tracewarn(a); 177 return 0; 178 } 179 180 for (i = 0; i < cert->ipsz; i++) { 181 if (valid_ip(a, cert->ips[i].afi, cert->ips[i].min, 182 cert->ips[i].max)) 183 continue; 184 switch (cert->ips[i].type) { 185 case CERT_IP_RANGE: 186 ip_addr_print(&cert->ips[i].range.min, 187 cert->ips[i].afi, buf1, sizeof(buf1)); 188 ip_addr_print(&cert->ips[i].range.max, 189 cert->ips[i].afi, buf2, sizeof(buf2)); 190 warnx("%s: RFC 6487: uncovered IP: " 191 "%s--%s", fn, buf1, buf2); 192 break; 193 case CERT_IP_ADDR: 194 ip_addr_print(&cert->ips[i].ip, 195 cert->ips[i].afi, buf1, sizeof(buf1)); 196 warnx("%s: RFC 6487: uncovered IP: " 197 "%s", fn, buf1); 198 case CERT_IP_INHERIT: 199 warnx("%s: RFC 6487: uncovered IP: " 200 "(inherit)", fn); 201 break; 202 } 203 tracewarn(a); 204 return 0; 205 } 206 207 return 1; 208 } 209 210 /* 211 * Validate our ROA: check that the SKI is unique, the AKI exists, and 212 * the IP prefix is also contained. 213 * Returns 1 if valid, 0 otherwise. 214 */ 215 int 216 valid_roa(const char *fn, struct auth_tree *auths, struct roa *roa) 217 { 218 struct auth *a; 219 size_t i; 220 char buf[64]; 221 222 a = valid_ski_aki(fn, auths, roa->ski, roa->aki); 223 if (a == NULL) 224 return 0; 225 226 if ((roa->tal = strdup(a->tal)) == NULL) 227 err(1, NULL); 228 229 for (i = 0; i < roa->ipsz; i++) { 230 if (valid_ip(a, roa->ips[i].afi, roa->ips[i].min, 231 roa->ips[i].max)) 232 continue; 233 ip_addr_print(&roa->ips[i].addr, 234 roa->ips[i].afi, buf, sizeof(buf)); 235 warnx("%s: RFC 6482: uncovered IP: " 236 "%s", fn, buf); 237 tracewarn(a); 238 return 0; 239 } 240 241 return 1; 242 } 243