@@ -119,6 +119,10 @@ struct ebox_config {
119
119
/* key for collecting challenge-responses */
120
120
struct sshkey * ec_chalkey ;
121
121
122
+ /* nonce for uniquifying recovery keys */
123
+ uint8_t * ec_nonce ;
124
+ size_t ec_noncelen ;
125
+
122
126
void * ec_priv ;
123
127
};
124
128
@@ -194,6 +198,7 @@ enum ebox_part_tag {
194
198
enum ebox_version {
195
199
EBOX_V1 = 0x01 ,
196
200
EBOX_V2 = 0x02 ,
201
+ EBOX_V3 = 0x03 ,
197
202
EBOX_VNEXT ,
198
203
EBOX_VMIN = EBOX_V1
199
204
};
@@ -1099,6 +1104,7 @@ ebox_config_free(struct ebox_config *config)
1099
1104
return ;
1100
1105
if (config -> ec_chalkey != NULL )
1101
1106
sshkey_free (config -> ec_chalkey );
1107
+ freezero (config -> ec_nonce , config -> ec_noncelen );
1102
1108
free (config -> ec_priv );
1103
1109
for (part = config -> ec_parts ; part != NULL ; part = npart ) {
1104
1110
npart = part -> ep_next ;
@@ -1944,6 +1950,20 @@ sshbuf_get_ebox_config(struct sshbuf *buf, const struct ebox *ebox,
1944
1950
"ebox config has unknown type: 0x%02x" , tconfig -> etc_type );
1945
1951
goto out ;
1946
1952
}
1953
+ if (ebox -> e_version >= EBOX_V3 ) {
1954
+ rc = sshbuf_get_string8 (buf , & config -> ec_nonce ,
1955
+ & config -> ec_noncelen );
1956
+ if (rc ) {
1957
+ err = ssherrf ("sshbuf_get_string8" , rc );
1958
+ goto out ;
1959
+ }
1960
+ if (config -> ec_noncelen > 0 &&
1961
+ tconfig -> etc_type != EBOX_RECOVERY ) {
1962
+ err = errf ("InvalidConfig" , NULL ,
1963
+ "ebox config is PRIMARY but has config nonce" );
1964
+ goto out ;
1965
+ }
1966
+ }
1947
1967
if (tconfig -> etc_type == EBOX_PRIMARY &&
1948
1968
tconfig -> etc_n > 1 ) {
1949
1969
err = errf ("InvalidConfig" , NULL ,
@@ -2276,6 +2296,19 @@ sshbuf_put_ebox_config(struct sshbuf *buf, struct ebox *ebox,
2276
2296
return (ssherrf ("sshbuf_put_u8" , rc ));
2277
2297
}
2278
2298
2299
+ if (config -> ec_noncelen > 0 && config -> ec_nonce != NULL ) {
2300
+ VERIFY3S (ebox -> e_version , >=, EBOX_V3 );
2301
+ VERIFY3S (tconfig -> etc_type , = = , EBOX_RECOVERY );
2302
+ rc = sshbuf_put_string8 (buf , config -> ec_nonce ,
2303
+ config -> ec_noncelen );
2304
+ if (rc )
2305
+ return (ssherrf ("sshbuf_put_string8" , rc ));
2306
+ } else {
2307
+ rc = sshbuf_put_u8 (buf , 0 );
2308
+ if (rc )
2309
+ return (ssherrf ("sshbuf_put_u8" , rc ));
2310
+ }
2311
+
2279
2312
part = config -> ec_parts ;
2280
2313
for (; part != NULL ; part = part -> ep_next ) {
2281
2314
if ((err = sshbuf_put_ebox_part (buf , ebox , part )))
@@ -2597,6 +2630,7 @@ ebox_create(const struct ebox_tpl *tpl, const uint8_t *key, size_t keylen,
2597
2630
struct ebox_part * ppart , * npart ;
2598
2631
size_t plainlen ;
2599
2632
uint8_t * plain ;
2633
+ uint8_t * configkey ;
2600
2634
struct sshbuf * buf ;
2601
2635
struct piv_ecdh_box * pbox ;
2602
2636
sss_Keyshare * share , * shares = NULL ;
@@ -2650,10 +2684,23 @@ ebox_create(const struct ebox_tpl *tpl, const uint8_t *key, size_t keylen,
2650
2684
/* sss_* only supports 32-byte keys */
2651
2685
VERIFY3U (box -> e_rcv_key .b_len , = = , 32 );
2652
2686
2687
+ nconfig -> ec_nonce = calloc (1 , box -> e_rcv_key .b_len );
2688
+ nconfig -> ec_noncelen = box -> e_rcv_key .b_len ;
2689
+ VERIFY (nconfig -> ec_nonce != NULL );
2690
+ arc4random_buf (nconfig -> ec_nonce , keylen );
2691
+
2692
+ configkey = calloc_conceal (1 , nconfig -> ec_noncelen );
2693
+ for (i = 0 ; i < nconfig -> ec_noncelen ; ++ i ) {
2694
+ configkey [i ] = nconfig -> ec_nonce [i ] ^
2695
+ box -> e_rcv_key .b_data [i ];
2696
+ }
2697
+
2653
2698
shareslen = tconfig -> etc_m * sizeof (sss_Keyshare );
2654
2699
shares = calloc_conceal (1 , shareslen );
2655
- sss_create_keyshares (shares , box -> e_rcv_key .b_data ,
2656
- tconfig -> etc_m , tconfig -> etc_n );
2700
+ sss_create_keyshares (shares , configkey , tconfig -> etc_m ,
2701
+ tconfig -> etc_n );
2702
+
2703
+ freezero (configkey , nconfig -> ec_noncelen );
2657
2704
}
2658
2705
2659
2706
ppart = NULL ;
@@ -2739,6 +2786,12 @@ ebox_unlock(struct ebox *ebox, struct ebox_config *config)
2739
2786
"least one part box to be unlocked" ));
2740
2787
}
2741
2788
2789
+ size_t
2790
+ ebox_config_nonce_len (const struct ebox_config * config )
2791
+ {
2792
+ return (config -> ec_noncelen );
2793
+ }
2794
+
2742
2795
errf_t *
2743
2796
ebox_recover (struct ebox * ebox , struct ebox_config * config )
2744
2797
{
@@ -2750,6 +2803,8 @@ ebox_recover(struct ebox *ebox, struct ebox_config *config)
2750
2803
errf_t * err ;
2751
2804
int rc ;
2752
2805
uint8_t tag ;
2806
+ uint8_t * configkey ;
2807
+ size_t cklen ;
2753
2808
sss_Keyshare * share , * shares = NULL ;
2754
2809
2755
2810
if (ebox -> e_key != NULL || ebox -> e_keylen > 0 ) {
@@ -2794,10 +2849,32 @@ ebox_recover(struct ebox *ebox, struct ebox_config *config)
2794
2849
goto out ;
2795
2850
}
2796
2851
2797
- ebox -> e_rcv_key .b_data = calloc_conceal (1 , sizeof (sss_Keyshare ));
2798
- ebox -> e_rcv_key .b_len = sizeof (sss_Keyshare );
2799
- sss_combine_keyshares (ebox -> e_rcv_key .b_data ,
2800
- (const sss_Keyshare * )shares , n );
2852
+ /* sss_* only supports 32-byte keys */
2853
+ ebox -> e_rcv_key .b_len = (cklen = 32 );
2854
+ ebox -> e_rcv_key .b_data = calloc_conceal (1 , cklen );
2855
+
2856
+ configkey = calloc_conceal (1 , cklen );
2857
+ sss_combine_keyshares (configkey , (const sss_Keyshare * )shares , n );
2858
+
2859
+ if (config -> ec_noncelen > 0 && config -> ec_nonce != NULL ) {
2860
+ if (config -> ec_noncelen < cklen ) {
2861
+ free (ebox -> e_rcv_key .b_data );
2862
+ freezero (configkey , cklen );
2863
+ freezero (shares , m * sizeof (sss_Keyshare ));
2864
+ return (errf ("RecoveryFailed" , errf ("BadConfigNonce" ,
2865
+ NULL , "recovery config nonce has bad length: %zu "
2866
+ "(need %zu bytes)" , config -> ec_noncelen , cklen ),
2867
+ "ebox recovery failed" ));
2868
+ }
2869
+ VERIFY3U (config -> ec_noncelen , = = , cklen );
2870
+ for (i = 0 ; i < cklen ; ++ i ) {
2871
+ ebox -> e_rcv_key .b_data [i ] = configkey [i ] ^
2872
+ config -> ec_nonce [i ];
2873
+ }
2874
+ } else {
2875
+ bcopy (configkey , ebox -> e_rcv_key .b_data , cklen );
2876
+ }
2877
+ free (configkey );
2801
2878
2802
2879
err = ebox_decrypt_recovery (ebox );
2803
2880
if (err ) {
0 commit comments