1 /* $NetBSD: dnssec-revoke.c,v 1.5 2020/05/24 19:46:11 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 /*! \file */ 15 16 #include <inttypes.h> 17 #include <stdbool.h> 18 #include <stdlib.h> 19 #include <unistd.h> 20 21 #include <isc/buffer.h> 22 #include <isc/commandline.h> 23 #include <isc/file.h> 24 #include <isc/hash.h> 25 #include <isc/mem.h> 26 #include <isc/print.h> 27 #include <isc/string.h> 28 #include <isc/util.h> 29 30 #include <dns/keyvalues.h> 31 #include <dns/result.h> 32 33 #include <dst/dst.h> 34 35 #if USE_PKCS11 36 #include <pk11/result.h> 37 #endif /* if USE_PKCS11 */ 38 39 #include "dnssectool.h" 40 41 const char *program = "dnssec-revoke"; 42 43 static isc_mem_t *mctx = NULL; 44 45 ISC_PLATFORM_NORETURN_PRE static void 46 usage(void) ISC_PLATFORM_NORETURN_POST; 47 48 static void 49 usage(void) { 50 fprintf(stderr, "Usage:\n"); 51 fprintf(stderr, " %s [options] keyfile\n\n", program); 52 fprintf(stderr, "Version: %s\n", VERSION); 53 #if USE_PKCS11 54 fprintf(stderr, 55 " -E engine: specify PKCS#11 provider " 56 "(default: %s)\n", 57 PK11_LIB_LOCATION); 58 #else /* if USE_PKCS11 */ 59 fprintf(stderr, " -E engine: specify OpenSSL engine\n"); 60 #endif /* if USE_PKCS11 */ 61 fprintf(stderr, " -f: force overwrite\n"); 62 fprintf(stderr, " -h: help\n"); 63 fprintf(stderr, " -K directory: use directory for key files\n"); 64 fprintf(stderr, " -r: remove old keyfiles after " 65 "creating revoked version\n"); 66 fprintf(stderr, " -v level: set level of verbosity\n"); 67 fprintf(stderr, " -V: print version information\n"); 68 fprintf(stderr, "Output:\n"); 69 fprintf(stderr, " K<name>+<alg>+<new id>.key, " 70 "K<name>+<alg>+<new id>.private\n"); 71 72 exit(-1); 73 } 74 75 int 76 main(int argc, char **argv) { 77 isc_result_t result; 78 const char *engine = NULL; 79 char const *filename = NULL; 80 char *dir = NULL; 81 char newname[1024], oldname[1024]; 82 char keystr[DST_KEY_FORMATSIZE]; 83 char *endp; 84 int ch; 85 dst_key_t *key = NULL; 86 uint32_t flags; 87 isc_buffer_t buf; 88 bool force = false; 89 bool removefile = false; 90 bool id = false; 91 92 if (argc == 1) { 93 usage(); 94 } 95 96 isc_mem_create(&mctx); 97 98 #if USE_PKCS11 99 pk11_result_register(); 100 #endif /* if USE_PKCS11 */ 101 dns_result_register(); 102 103 isc_commandline_errprint = false; 104 105 while ((ch = isc_commandline_parse(argc, argv, "E:fK:rRhv:V")) != -1) { 106 switch (ch) { 107 case 'E': 108 engine = isc_commandline_argument; 109 break; 110 case 'f': 111 force = true; 112 break; 113 case 'K': 114 /* 115 * We don't have to copy it here, but do it to 116 * simplify cleanup later 117 */ 118 dir = isc_mem_strdup(mctx, isc_commandline_argument); 119 break; 120 case 'r': 121 removefile = true; 122 break; 123 case 'R': 124 id = true; 125 break; 126 case 'v': 127 verbose = strtol(isc_commandline_argument, &endp, 0); 128 if (*endp != '\0') { 129 fatal("-v must be followed by a number"); 130 } 131 break; 132 case '?': 133 if (isc_commandline_option != '?') { 134 fprintf(stderr, "%s: invalid argument -%c\n", 135 program, isc_commandline_option); 136 } 137 /* FALLTHROUGH */ 138 case 'h': 139 /* Does not return. */ 140 usage(); 141 142 case 'V': 143 /* Does not return. */ 144 version(program); 145 146 default: 147 fprintf(stderr, "%s: unhandled option -%c\n", program, 148 isc_commandline_option); 149 exit(1); 150 } 151 } 152 153 if (argc < isc_commandline_index + 1 || 154 argv[isc_commandline_index] == NULL) { 155 fatal("The key file name was not specified"); 156 } 157 if (argc > isc_commandline_index + 1) { 158 fatal("Extraneous arguments"); 159 } 160 161 if (dir != NULL) { 162 filename = argv[isc_commandline_index]; 163 } else { 164 result = isc_file_splitpath(mctx, argv[isc_commandline_index], 165 &dir, &filename); 166 if (result != ISC_R_SUCCESS) { 167 fatal("cannot process filename %s: %s", 168 argv[isc_commandline_index], 169 isc_result_totext(result)); 170 } 171 if (strcmp(dir, ".") == 0) { 172 isc_mem_free(mctx, dir); 173 dir = NULL; 174 } 175 } 176 177 result = dst_lib_init(mctx, engine); 178 if (result != ISC_R_SUCCESS) { 179 fatal("Could not initialize dst: %s", 180 isc_result_totext(result)); 181 } 182 183 result = dst_key_fromnamedfile( 184 filename, dir, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, mctx, &key); 185 if (result != ISC_R_SUCCESS) { 186 fatal("Invalid keyfile name %s: %s", filename, 187 isc_result_totext(result)); 188 } 189 190 if (id) { 191 fprintf(stdout, "%u\n", dst_key_rid(key)); 192 goto cleanup; 193 } 194 dst_key_format(key, keystr, sizeof(keystr)); 195 196 if (verbose > 2) { 197 fprintf(stderr, "%s: %s\n", program, keystr); 198 } 199 200 if (force) { 201 set_keyversion(key); 202 } else { 203 check_keyversion(key, keystr); 204 } 205 206 flags = dst_key_flags(key); 207 if ((flags & DNS_KEYFLAG_REVOKE) == 0) { 208 isc_stdtime_t now; 209 210 if ((flags & DNS_KEYFLAG_KSK) == 0) { 211 fprintf(stderr, 212 "%s: warning: Key is not flagged " 213 "as a KSK. Revoking a ZSK is " 214 "legal, but undefined.\n", 215 program); 216 } 217 218 isc_stdtime_get(&now); 219 dst_key_settime(key, DST_TIME_REVOKE, now); 220 221 dst_key_setflags(key, flags | DNS_KEYFLAG_REVOKE); 222 223 isc_buffer_init(&buf, newname, sizeof(newname)); 224 dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); 225 226 if (access(newname, F_OK) == 0 && !force) { 227 fatal("Key file %s already exists; " 228 "use -f to force overwrite", 229 newname); 230 } 231 232 result = dst_key_tofile(key, DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, 233 dir); 234 if (result != ISC_R_SUCCESS) { 235 dst_key_format(key, keystr, sizeof(keystr)); 236 fatal("Failed to write key %s: %s", keystr, 237 isc_result_totext(result)); 238 } 239 240 isc_buffer_clear(&buf); 241 dst_key_buildfilename(key, 0, dir, &buf); 242 printf("%s\n", newname); 243 244 /* 245 * Remove old key file, if told to (and if 246 * it isn't the same as the new file) 247 */ 248 if (removefile) { 249 isc_buffer_init(&buf, oldname, sizeof(oldname)); 250 dst_key_setflags(key, flags & ~DNS_KEYFLAG_REVOKE); 251 dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); 252 if (strcmp(oldname, newname) == 0) { 253 goto cleanup; 254 } 255 (void)unlink(oldname); 256 isc_buffer_clear(&buf); 257 dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); 258 (void)unlink(oldname); 259 } 260 } else { 261 dst_key_format(key, keystr, sizeof(keystr)); 262 fatal("Key %s is already revoked", keystr); 263 } 264 265 cleanup: 266 dst_key_free(&key); 267 dst_lib_destroy(); 268 if (verbose > 10) { 269 isc_mem_stats(mctx, stdout); 270 } 271 if (dir != NULL) { 272 isc_mem_free(mctx, dir); 273 } 274 isc_mem_destroy(&mctx); 275 276 return (0); 277 } 278