@@ -69,6 +69,8 @@ int PEM_write_X509(FILE *fp, X509 *x);
69
69
boolean_t debug = B_FALSE ;
70
70
static boolean_t parseable = B_FALSE ;
71
71
static const char * cn = NULL ;
72
+ static const char * upn = NULL ;
73
+ static boolean_t save_pinfo_admin = B_TRUE ;
72
74
static uint8_t * guid = NULL ;
73
75
static size_t guid_len = 0 ;
74
76
static uint min_retries = 1 ;
@@ -542,6 +544,90 @@ cmd_list(void)
542
544
return (ERRF_OK );
543
545
}
544
546
547
+ static errf_t *
548
+ save_pinfo_admin_key (struct piv_token * tk )
549
+ {
550
+ struct tlv_state * tlv ;
551
+ errf_t * err ;
552
+
553
+ tlv = tlv_init_write ();
554
+ tlv_push (tlv , 0x88 );
555
+ tlv_push (tlv , 0x89 );
556
+ tlv_write (tlv , admin_key , 24 );
557
+ tlv_pop (tlv );
558
+ tlv_pop (tlv );
559
+
560
+ err = piv_write_file (tk , PIV_TAG_PRINTINFO ,
561
+ tlv_buf (tlv ), tlv_len (tlv ));
562
+ tlv_free (tlv );
563
+ return (err );
564
+ }
565
+
566
+ static errf_t *
567
+ try_pinfo_admin_key (struct piv_token * tk )
568
+ {
569
+ uint8_t * data = NULL ;
570
+ size_t dlen = 0 ;
571
+ errf_t * err ;
572
+ uint tag ;
573
+ struct tlv_state * tlv = NULL ;
574
+
575
+ assert_pin (tk , B_FALSE );
576
+ again :
577
+ err = piv_read_file (tk , PIV_TAG_PRINTINFO , & data , & dlen );
578
+ if (err && errf_caused_by (err , "PermissionError" )) {
579
+ assert_pin (tk , B_TRUE );
580
+ goto again ;
581
+ }
582
+ if (err == ERRF_OK ) {
583
+ tlv = tlv_init (data , 0 , dlen );
584
+ while (!tlv_at_end (tlv )) {
585
+ if ((err = tlv_read_tag (tlv , & tag )))
586
+ goto out ;
587
+ if (tag == 0x88 ) {
588
+ if ((err = tlv_read_tag (tlv , & tag )))
589
+ goto out ;
590
+ if (tag == 0x89 ) {
591
+ uint8_t * key ;
592
+ size_t keylen ;
593
+ err = tlv_read_alloc (tlv , & key ,
594
+ & keylen );
595
+ if (err )
596
+ goto out ;
597
+ if ((err = tlv_end (tlv )))
598
+ goto out ;
599
+ if (keylen == 24 ) {
600
+ admin_key = key ;
601
+ err = ERRF_OK ;
602
+ } else {
603
+ err = errf ("BadLength" , NULL ,
604
+ "Data is wrong length for "
605
+ "an admin key (%d bytes)" ,
606
+ keylen );
607
+ goto out ;
608
+ }
609
+ } else {
610
+ tlv_skip (tlv );
611
+ }
612
+ if ((err = tlv_end (tlv )))
613
+ goto out ;
614
+ } else {
615
+ tlv_skip (tlv );
616
+ }
617
+ }
618
+ bunyan_log (BNY_DEBUG , "using admin key from printedinfo file" ,
619
+ NULL );
620
+ tlv_free (tlv );
621
+ tlv = NULL ;
622
+ }
623
+
624
+ out :
625
+ if (tlv != NULL )
626
+ tlv_abort (tlv );
627
+ freezero (data , dlen );
628
+ return (err );
629
+ }
630
+
545
631
static errf_t *
546
632
cmd_init (void )
547
633
{
@@ -628,7 +714,14 @@ cmd_init(void)
628
714
if ((err = piv_txn_begin (selk )))
629
715
return (err );
630
716
assert_select (selk );
717
+ admin_again :
631
718
err = piv_auth_admin (selk , admin_key , 24 );
719
+ if (err && errf_caused_by (err , "PermissionError" ) &&
720
+ admin_key == DEFAULT_ADMIN_KEY ) {
721
+ err = try_pinfo_admin_key (selk );
722
+ if (err == ERRF_OK )
723
+ goto admin_again ;
724
+ }
632
725
if (err == ERRF_OK ) {
633
726
err = piv_write_file (selk , PIV_TAG_CARDCAP ,
634
727
tlv_buf (ccc ), tlv_len (ccc ));
@@ -679,6 +772,13 @@ cmd_set_admin(uint8_t *new_admin_key)
679
772
if (err ) {
680
773
err = funcerrf (err , "Failed to set new admin key" );
681
774
}
775
+ if (!err && save_pinfo_admin ) {
776
+ admin_key = new_admin_key ;
777
+ if ((err = save_pinfo_admin_key (selk ))) {
778
+ err = funcerrf (err , "Failed to write new "
779
+ "admin key to printed info object" );
780
+ }
781
+ }
682
782
}
683
783
piv_txn_end (selk );
684
784
@@ -890,7 +990,7 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
890
990
X509 * cert ;
891
991
EVP_PKEY * pkey ;
892
992
X509_NAME * subj ;
893
- const char * ku , * basic ;
993
+ const char * ku , * basic , * eku = NULL ;
894
994
char * name ;
895
995
enum sshdigest_types wantalg , hashalg ;
896
996
int nid ;
@@ -904,30 +1004,38 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
904
1004
X509_EXTENSION * ext ;
905
1005
X509V3_CTX x509ctx ;
906
1006
const char * guidhex ;
1007
+ const char * myupn = upn ;
1008
+ const char * mycn = cn ;
907
1009
908
- guidhex = piv_token_guid_hex (selk );
1010
+ guidhex = piv_token_shortid (selk );
1011
+
1012
+ name = calloc (1 , 64 );
909
1013
910
1014
switch (slotid ) {
911
1015
case 0x9A :
912
- name = "piv-auth" ;
1016
+ snprintf ( name , 64 , "piv-auth@%s" , guidhex ) ;
913
1017
basic = "critical,CA:FALSE" ;
914
1018
ku = "critical,digitalSignature,nonRepudiation" ;
1019
+ eku = "clientAuth,1.3.6.1.4.1.311.20.2.2" ;
1020
+ if (myupn == NULL )
1021
+ myupn = getenv ("LOGNAME" );
915
1022
break ;
916
1023
case 0x9C :
917
- name = "piv-sign" ;
1024
+ snprintf ( name , 64 , "piv-sign@%s" , guidhex ) ;
918
1025
basic = "critical,CA:TRUE" ;
919
1026
ku = "critical,digitalSignature,nonRepudiation,"
920
1027
"keyCertSign,cRLSign" ;
921
1028
break ;
922
1029
case 0x9D :
923
- name = "piv-key-mgmt" ;
1030
+ snprintf ( name , 64 , "piv-key-mgmt@%s" , guidhex ) ;
924
1031
basic = "critical,CA:FALSE" ;
925
1032
ku = "critical,keyAgreement,keyEncipherment,dataEncipherment" ;
926
1033
break ;
927
1034
case 0x9E :
928
- name = "piv-card-auth" ;
1035
+ snprintf ( name , 64 , "piv-card-auth@%s" , guidhex ) ;
929
1036
basic = "critical,CA:FALSE" ;
930
1037
ku = "critical,digitalSignature,nonRepudiation" ;
1038
+ eku = "clientAuth" ;
931
1039
break ;
932
1040
case 0x82 :
933
1041
case 0x83 :
@@ -949,8 +1057,7 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
949
1057
case 0x93 :
950
1058
case 0x94 :
951
1059
case 0x95 :
952
- name = calloc (1 , 64 );
953
- snprintf (name , 64 , "piv-retired-%u" , slotid - 0x81 );
1060
+ snprintf (name , 64 , "piv-retired-%u@%s" , slotid - 0x81 , guidhex );
954
1061
basic = "critical,CA:FALSE" ;
955
1062
ku = "critical,digitalSignature,nonRepudiation" ;
956
1063
if (slotid - 0x82 > piv_token_keyhistory_oncard (selk )) {
@@ -966,6 +1073,17 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
966
1073
return (err );
967
1074
}
968
1075
1076
+ if (myupn != NULL && eku == NULL ) {
1077
+ eku = "clientAuth,1.3.6.1.4.1.311.20.2.2" ;
1078
+ }
1079
+
1080
+ if (myupn != NULL ) {
1081
+ char * newupn = calloc (1 , 128 );
1082
+ snprintf (newupn , 128 ,
1083
+ "otherName:1.3.6.1.4.1.311.20.2.3;UTF8:%s" , myupn );
1084
+ myupn = newupn ;
1085
+ }
1086
+
969
1087
pkey = EVP_PKEY_new ();
970
1088
VERIFY (pkey != NULL );
971
1089
if (pub -> type == KEY_RSA ) {
@@ -1021,15 +1139,11 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
1021
1139
1022
1140
subj = X509_NAME_new ();
1023
1141
VERIFY (subj != NULL );
1024
- if (cn == NULL ) {
1025
- VERIFY (X509_NAME_add_entry_by_NID (subj , NID_title , MBSTRING_ASC ,
1026
- (unsigned char * )name , -1 , -1 , 0 ) == 1 );
1027
- VERIFY (X509_NAME_add_entry_by_NID (subj , NID_commonName ,
1028
- MBSTRING_ASC , (unsigned char * )guidhex , -1 , -1 , 0 ) == 1 );
1029
- } else {
1030
- VERIFY (X509_NAME_add_entry_by_NID (subj , NID_commonName ,
1031
- MBSTRING_ASC , (unsigned char * )cn , -1 , -1 , 0 ) == 1 );
1142
+ if (mycn == NULL ) {
1143
+ mycn = name ;
1032
1144
}
1145
+ VERIFY (X509_NAME_add_entry_by_NID (subj , NID_commonName ,
1146
+ MBSTRING_ASC , (unsigned char * )mycn , -1 , -1 , 0 ) == 1 );
1033
1147
/*VERIFY(X509_NAME_add_entry_by_NID(subj, NID_organizationalUnitName,
1034
1148
MBSTRING_ASC, (unsigned char *)"tokens", -1, -1, 0) == 1);
1035
1149
VERIFY(X509_NAME_add_entry_by_NID(subj, NID_organizationName,
@@ -1051,6 +1165,22 @@ selfsign_slot(uint slotid, enum piv_alg alg, struct sshkey *pub)
1051
1165
X509_add_ext (cert , ext , -1 );
1052
1166
X509_EXTENSION_free (ext );
1053
1167
1168
+ if (eku != NULL ) {
1169
+ ext = X509V3_EXT_conf_nid (NULL , & x509ctx , NID_ext_key_usage ,
1170
+ (char * )eku );
1171
+ VERIFY (ext != NULL );
1172
+ X509_add_ext (cert , ext , -1 );
1173
+ X509_EXTENSION_free (ext );
1174
+ }
1175
+
1176
+ if (myupn != NULL ) {
1177
+ ext = X509V3_EXT_conf_nid (NULL , & x509ctx , NID_subject_alt_name ,
1178
+ (char * )myupn );
1179
+ VERIFY (ext != NULL );
1180
+ X509_add_ext (cert , ext , -1 );
1181
+ X509_EXTENSION_free (ext );
1182
+ }
1183
+
1054
1184
VERIFY (X509_set_pubkey (cert , pkey ) == 1 );
1055
1185
1056
1186
cert -> sig_alg -> algorithm = OBJ_nid2obj (nid );
@@ -1185,7 +1315,14 @@ cmd_import(uint slotid)
1185
1315
if ((err = piv_txn_begin (selk )))
1186
1316
return (err );
1187
1317
assert_select (selk );
1318
+ admin_again :
1188
1319
err = piv_auth_admin (selk , admin_key , 24 );
1320
+ if (err && errf_caused_by (err , "PermissionError" ) &&
1321
+ admin_key == DEFAULT_ADMIN_KEY ) {
1322
+ err = try_pinfo_admin_key (selk );
1323
+ if (err == ERRF_OK )
1324
+ goto admin_again ;
1325
+ }
1189
1326
if (err == ERRF_OK ) {
1190
1327
err = ykpiv_import (selk , slotid , priv , pinpolicy , touchpolicy );
1191
1328
}
@@ -1241,7 +1378,14 @@ cmd_generate(uint slotid, enum piv_alg alg)
1241
1378
if ((err = piv_txn_begin (selk )))
1242
1379
return (err );
1243
1380
assert_select (selk );
1381
+ admin_again :
1244
1382
err = piv_auth_admin (selk , admin_key , 24 );
1383
+ if (err && errf_caused_by (err , "PermissionError" ) &&
1384
+ admin_key == DEFAULT_ADMIN_KEY ) {
1385
+ err = try_pinfo_admin_key (selk );
1386
+ if (err == ERRF_OK )
1387
+ goto admin_again ;
1388
+ }
1245
1389
if (err == ERRF_OK ) {
1246
1390
if (pinpolicy == YKPIV_PIN_DEFAULT &&
1247
1391
touchpolicy == YKPIV_TOUCH_DEFAULT ) {
@@ -2033,15 +2177,15 @@ cmd_setup(SCARDCONTEXT ctx)
2033
2177
arc4random_buf (admin_key , 24 );
2034
2178
if (usetouch )
2035
2179
touchpolicy = YKPIV_TOUCH_ALWAYS ;
2036
- hex = buf_to_hex (admin_key , 24 , B_FALSE );
2037
- printf ("Admin 3DES key: %s\n" , hex );
2038
- fprintf (stderr , "This key is only needed to generate new slot keys or "
2039
- "change certificates in future. If you don't intend to do either "
2040
- "you can simply forget about this key and the Yubikey will be "
2041
- "sealed.\n" );
2180
+
2042
2181
if ((err = cmd_set_admin (admin_key )))
2043
2182
return (err );
2044
2183
2184
+ if (!save_pinfo_admin ) {
2185
+ hex = buf_to_hex (admin_key , 24 , B_FALSE );
2186
+ printf ("Admin 3DES key: %s\n" , hex );
2187
+ }
2188
+
2045
2189
fprintf (stderr , "Done!\n" );
2046
2190
2047
2191
return (ERRF_OK );
@@ -2119,6 +2263,8 @@ usage(void)
2119
2263
" RSA algos: rsa1024, rsa2048, rsa4096\n"
2120
2264
" -n <cn> Set a CN= attribute to be used on\n"
2121
2265
" the new slot's certificate\n"
2266
+ " -u <upn> Set a UPN= attribute to be used on\n"
2267
+ " the new slot's certificate\n"
2122
2268
" -t <never|always|cached>\n"
2123
2269
" Set the touch policy. Only supported\n"
2124
2270
" with YubiKeys\n"
@@ -2127,7 +2273,12 @@ usage(void)
2127
2273
"\n"
2128
2274
"Options for 'box'/'unbox':\n"
2129
2275
" -k <pubkey> Use a public key for box operation\n"
2130
- " instead of a slot\n" );
2276
+ " instead of a slot\n"
2277
+ "\n"
2278
+ "Options for 'set-admin'/'setup':\n"
2279
+ " -R Don't save admin key in the PIV\n"
2280
+ " 'printed info' object (compat with\n"
2281
+ " Yubico PIV manager)\n" );
2131
2282
exit (EXIT_BAD_ARGS );
2132
2283
}
2133
2284
@@ -2140,7 +2291,7 @@ usage(void)
2140
2291
"f(force)"
2141
2292
"K:(admin-key)"
2142
2293
"k:(key)";*/
2143
- const char * optstring = "dpg:P:a:fK:k:n:t:i:" ;
2294
+ const char * optstring = "dpg:P:a:fK:k:n:t:i:u:R " ;
2144
2295
2145
2296
int
2146
2297
main (int argc , char * argv [])
@@ -2167,6 +2318,9 @@ main(int argc, char *argv[])
2167
2318
if (++ d_level > 1 )
2168
2319
piv_full_apdu_debug = B_TRUE ;
2169
2320
break ;
2321
+ case 'R' :
2322
+ save_pinfo_admin = B_FALSE ;
2323
+ break ;
2170
2324
case 'K' :
2171
2325
if (strcmp (optarg , "default" ) == 0 ) {
2172
2326
admin_key = DEFAULT_ADMIN_KEY ;
@@ -2186,6 +2340,9 @@ main(int argc, char *argv[])
2186
2340
"24 bytes in length (%d given)" , len );
2187
2341
}
2188
2342
break ;
2343
+ case 'u' :
2344
+ upn = optarg ;
2345
+ break ;
2189
2346
case 'n' :
2190
2347
cn = optarg ;
2191
2348
break ;
0 commit comments