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