diff --git a/man/scdtotp.1.in b/man/scdtotp.1.in index a2ac171..94657bf 100644 --- a/man/scdtotp.1.in +++ b/man/scdtotp.1.in @@ -15,6 +15,8 @@ scdtotp \- Generate one-time passwords from an OpenPGP smartcard .IR N ] .RB [ \-m | --mac-algo .IR algo ] +.RB [ \-n | --private-do +.IR N ] .YS .SH DESCRIPTION @@ -52,6 +54,10 @@ digits. .BR -m ", " --mac-algo " " \fialgo\fR Select the HMAC algorithm to use among \fisha1\fR (default), \fisha256\fR, or \fisha512\fR. +.TP +.BR -n ", " --private-do " " \fiN\fR +Read key from private DO slot #\fiN\fR +(default is 1). .SH REPORTING BUGS .PP diff --git a/src/scdtotp.c b/src/scdtotp.c index 1490454..8b574f1 100644 --- a/src/scdtotp.c +++ b/src/scdtotp.c @@ -35,6 +35,7 @@ #define DEFAULT_TIME_STEP 30 #define DEFAULT_DIGITS 6 #define MAX_KEY_SIZE 64 +#define DEFAULT_PRIVATE_DO 1 static void usage(int status) @@ -64,6 +65,11 @@ found in a OpenPGP smartcard.\n\ 'sha256' or 'sha512'.\n\ "); + printf("\n\ + -n, --private-do N Read key from private data object N\n\ + (default is %d).\n\ +", DEFAULT_PRIVATE_DO); + printf("Report bugs to <%s>.\n", PACKAGE_BUGREPORT); exit(status); @@ -262,7 +268,7 @@ get_otp_key_cb(void *arg, const char *line) { struct key_data_t *key = (struct key_data_t *)arg; - if ( ! strncmp("PRIVATE-DO-1", line, 12) ) { + if ( ! strncmp("PRIVATE-DO-", line, 11) ) { const char *cursor; size_t n; @@ -291,19 +297,25 @@ get_otp_key_cb(void *arg, const char *line) * @return 0 if successful, or a gpg_error_t error code. */ static gpg_error_t -get_otp_key(unsigned char *buffer, size_t len) +get_otp_key(unsigned privatedo, unsigned char *buffer, size_t len) { assuan_context_t ctx; gpg_error_t e; struct key_data_t key; + char command[32]; key.buffer = buffer; key.len = len; key.found = 0; + if ( privatedo < 1 || privatedo > 4 ) + return gcry_error(GPG_ERR_INV_ARG); + if ( ! (e = connect_to_scdaemon(&ctx)) ) { - if ( ! (e = assuan_transact(ctx, "GETATTR PRIVATE-DO-1", NULL, NULL, + snprintf(command, sizeof(command), "GETATTR PRIVATE-DO-%d", privatedo); + + if ( ! (e = assuan_transact(ctx, command, NULL, NULL, NULL, NULL, get_otp_key_cb, &key)) ) { if ( key.found ) e = gcry_error(GPG_ERR_NO_ERROR); @@ -345,7 +357,7 @@ main(int argc, char **argv) { int c, algo; unsigned char key[MAX_KEY_SIZE * 2 + 1]; - unsigned otp, step, digits; + unsigned otp, step, digits, privatedo; time_t secs; gcry_error_t e; @@ -356,6 +368,7 @@ main(int argc, char **argv) { "step", 1, NULL, 's' }, { "digits", 1, NULL, 'd' }, { "mac-algo", 1, NULL, 'm' }, + { "private-do", 1, NULL, 'n' }, { NULL, 0, NULL, 0 } }; @@ -364,8 +377,9 @@ main(int argc, char **argv) step = DEFAULT_TIME_STEP; digits = DEFAULT_DIGITS; algo = GCRY_MAC_HMAC_SHA1; + privatedo = DEFAULT_PRIVATE_DO; - while ( (c = getopt_long(argc, argv, "hvt:s:d:m:", + while ( (c = getopt_long(argc, argv, "hvt:s:d:m:n:", options, NULL)) != -1 ) { switch ( c ) { case 'h': @@ -404,6 +418,12 @@ main(int argc, char **argv) else errx(EXIT_FAILURE, "unsupported HMAC algorithm: %s", optarg); break; + + case 'n': + privatedo = get_uinteger_or_die(optarg); + if ( privatedo < 1 || privatedo > 4 ) + errx(EXIT_FAILURE, "DO number must be 1, 2, 3, or 4"); + break; } } @@ -413,7 +433,7 @@ main(int argc, char **argv) gcry_control(GCRYCTL_DISABLE_SECMEM, 0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); - if ( (e = get_otp_key(key, sizeof(key))) ) + if ( (e = get_otp_key(privatedo, key, sizeof(key))) ) errx(EXIT_FAILURE, "Cannot get key from token: %s", gcry_strerror(e)); if ( (e = generate_totp(algo, key, secs, step, digits, &otp)) )