1 /* $NetBSD: dnssec-revoke.c,v 1.8 2014/12/10 04:37:51 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2009-2012, 2014 Internet Systems Consortium, Inc. ("ISC") 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 11 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 12 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 13 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 14 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 15 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /*! \file */ 20 21 #include <config.h> 22 23 #include <stdlib.h> 24 #include <unistd.h> 25 26 #include <isc/buffer.h> 27 #include <isc/commandline.h> 28 #include <isc/entropy.h> 29 #include <isc/file.h> 30 #include <isc/hash.h> 31 #include <isc/mem.h> 32 #include <isc/print.h> 33 #include <isc/string.h> 34 #include <isc/util.h> 35 36 #include <dns/keyvalues.h> 37 #include <dns/result.h> 38 39 #include <dst/dst.h> 40 41 #ifdef PKCS11CRYPTO 42 #include <pk11/result.h> 43 #endif 44 45 #include "dnssectool.h" 46 47 const char *program = "dnssec-revoke"; 48 int verbose; 49 50 static isc_mem_t *mctx = NULL; 51 52 ISC_PLATFORM_NORETURN_PRE static void 53 usage(void) ISC_PLATFORM_NORETURN_POST; 54 55 static void 56 usage(void) { 57 fprintf(stderr, "Usage:\n"); 58 fprintf(stderr, " %s [options] keyfile\n\n", program); 59 fprintf(stderr, "Version: %s\n", VERSION); 60 #if defined(PKCS11CRYPTO) 61 fprintf(stderr, " -E engine: specify PKCS#11 provider " 62 "(default: %s)\n", PK11_LIB_LOCATION); 63 #elif defined(USE_PKCS11) 64 fprintf(stderr, " -E engine: specify OpenSSL engine " 65 "(default \"pkcs11\")\n"); 66 #else 67 fprintf(stderr, " -E engine: specify OpenSSL engine\n"); 68 #endif 69 fprintf(stderr, " -f: force overwrite\n"); 70 fprintf(stderr, " -K directory: use directory for key files\n"); 71 fprintf(stderr, " -h: help\n"); 72 fprintf(stderr, " -r: remove old keyfiles after " 73 "creating revoked version\n"); 74 fprintf(stderr, " -v level: set level of verbosity\n"); 75 fprintf(stderr, " -V: print version information\n"); 76 fprintf(stderr, "Output:\n"); 77 fprintf(stderr, " K<name>+<alg>+<new id>.key, " 78 "K<name>+<alg>+<new id>.private\n"); 79 80 exit (-1); 81 } 82 83 int 84 main(int argc, char **argv) { 85 isc_result_t result; 86 #ifdef USE_PKCS11 87 const char *engine = PKCS11_ENGINE; 88 #else 89 const char *engine = NULL; 90 #endif 91 char *filename = NULL, *dir = NULL; 92 char newname[1024], oldname[1024]; 93 char keystr[DST_KEY_FORMATSIZE]; 94 char *endp; 95 int ch; 96 isc_entropy_t *ectx = NULL; 97 dst_key_t *key = NULL; 98 isc_uint32_t flags; 99 isc_buffer_t buf; 100 isc_boolean_t force = ISC_FALSE; 101 isc_boolean_t remove = ISC_FALSE; 102 isc_boolean_t id = ISC_FALSE; 103 104 if (argc == 1) 105 usage(); 106 107 result = isc_mem_create(0, 0, &mctx); 108 if (result != ISC_R_SUCCESS) 109 fatal("Out of memory"); 110 111 #ifdef PKCS11CRYPTO 112 pk11_result_register(); 113 #endif 114 dns_result_register(); 115 116 isc_commandline_errprint = ISC_FALSE; 117 118 while ((ch = isc_commandline_parse(argc, argv, "E:fK:rRhv:V")) != -1) { 119 switch (ch) { 120 case 'E': 121 engine = isc_commandline_argument; 122 break; 123 case 'f': 124 force = ISC_TRUE; 125 break; 126 case 'K': 127 /* 128 * We don't have to copy it here, but do it to 129 * simplify cleanup later 130 */ 131 dir = isc_mem_strdup(mctx, isc_commandline_argument); 132 if (dir == NULL) { 133 fatal("Failed to allocate memory for " 134 "directory"); 135 } 136 break; 137 case 'r': 138 remove = ISC_TRUE; 139 break; 140 case 'R': 141 id = ISC_TRUE; 142 break; 143 case 'v': 144 verbose = strtol(isc_commandline_argument, &endp, 0); 145 if (*endp != '\0') 146 fatal("-v must be followed by a number"); 147 break; 148 case '?': 149 if (isc_commandline_option != '?') 150 fprintf(stderr, "%s: invalid argument -%c\n", 151 program, isc_commandline_option); 152 /* Falls into */ 153 case 'h': 154 /* Does not return. */ 155 usage(); 156 157 case 'V': 158 /* Does not return. */ 159 version(program); 160 161 default: 162 fprintf(stderr, "%s: unhandled option -%c\n", 163 program, isc_commandline_option); 164 exit(1); 165 } 166 } 167 168 if (argc < isc_commandline_index + 1 || 169 argv[isc_commandline_index] == NULL) 170 fatal("The key file name was not specified"); 171 if (argc > isc_commandline_index + 1) 172 fatal("Extraneous arguments"); 173 174 if (dir != NULL) { 175 filename = argv[isc_commandline_index]; 176 } else { 177 result = isc_file_splitpath(mctx, argv[isc_commandline_index], 178 &dir, &filename); 179 if (result != ISC_R_SUCCESS) 180 fatal("cannot process filename %s: %s", 181 argv[isc_commandline_index], 182 isc_result_totext(result)); 183 if (strcmp(dir, ".") == 0) { 184 isc_mem_free(mctx, dir); 185 dir = NULL; 186 } 187 } 188 189 if (ectx == NULL) 190 setup_entropy(mctx, NULL, &ectx); 191 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); 192 if (result != ISC_R_SUCCESS) 193 fatal("Could not initialize hash"); 194 result = dst_lib_init2(mctx, ectx, engine, 195 ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); 196 if (result != ISC_R_SUCCESS) 197 fatal("Could not initialize dst: %s", 198 isc_result_totext(result)); 199 isc_entropy_stopcallbacksources(ectx); 200 201 result = dst_key_fromnamedfile(filename, dir, 202 DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, 203 mctx, &key); 204 if (result != ISC_R_SUCCESS) 205 fatal("Invalid keyfile name %s: %s", 206 filename, isc_result_totext(result)); 207 208 if (id) { 209 fprintf(stdout, "%u\n", dst_key_rid(key)); 210 goto cleanup; 211 } 212 dst_key_format(key, keystr, sizeof(keystr)); 213 214 if (verbose > 2) 215 fprintf(stderr, "%s: %s\n", program, keystr); 216 217 if (force) 218 set_keyversion(key); 219 else 220 check_keyversion(key, keystr); 221 222 223 flags = dst_key_flags(key); 224 if ((flags & DNS_KEYFLAG_REVOKE) == 0) { 225 isc_stdtime_t now; 226 227 if ((flags & DNS_KEYFLAG_KSK) == 0) 228 fprintf(stderr, "%s: warning: Key is not flagged " 229 "as a KSK. Revoking a ZSK is " 230 "legal, but undefined.\n", 231 program); 232 233 isc_stdtime_get(&now); 234 dst_key_settime(key, DST_TIME_REVOKE, now); 235 236 dst_key_setflags(key, flags | DNS_KEYFLAG_REVOKE); 237 238 isc_buffer_init(&buf, newname, sizeof(newname)); 239 dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); 240 241 if (access(newname, F_OK) == 0 && !force) { 242 fatal("Key file %s already exists; " 243 "use -f to force overwrite", newname); 244 } 245 246 result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, 247 dir); 248 if (result != ISC_R_SUCCESS) { 249 dst_key_format(key, keystr, sizeof(keystr)); 250 fatal("Failed to write key %s: %s", keystr, 251 isc_result_totext(result)); 252 } 253 254 isc_buffer_clear(&buf); 255 dst_key_buildfilename(key, 0, dir, &buf); 256 printf("%s\n", newname); 257 258 /* 259 * Remove old key file, if told to (and if 260 * it isn't the same as the new file) 261 */ 262 if (remove && dst_key_alg(key) != DST_ALG_RSAMD5) { 263 isc_buffer_init(&buf, oldname, sizeof(oldname)); 264 dst_key_setflags(key, flags & ~DNS_KEYFLAG_REVOKE); 265 dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); 266 if (strcmp(oldname, newname) == 0) 267 goto cleanup; 268 (void)unlink(oldname); 269 isc_buffer_clear(&buf); 270 dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); 271 (void)unlink(oldname); 272 } 273 } else { 274 dst_key_format(key, keystr, sizeof(keystr)); 275 fatal("Key %s is already revoked", keystr); 276 } 277 278 cleanup: 279 dst_key_free(&key); 280 dst_lib_destroy(); 281 isc_hash_destroy(); 282 cleanup_entropy(&ectx); 283 if (verbose > 10) 284 isc_mem_stats(mctx, stdout); 285 if (dir != NULL) 286 isc_mem_free(mctx, dir); 287 isc_mem_destroy(&mctx); 288 289 return (0); 290 } 291