Commit 27e4de2bd1804c24e3e517dd54026c1f60e8fe27
Committed by
Herbert Xu
1 parent
4f15071879
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
crypto: drbg - Mix a time stamp into DRBG state
The current locking approach of the DRBG tries to keep the protected code paths very minimal. It is therefore possible that two threads query one DRBG instance at the same time. When thread A requests random numbers, a shadow copy of the DRBG state is created upon which the request for A is processed. After finishing the state for A's request is merged back into the DRBG state. If now thread B requests random numbers from the same DRBG after the request for thread A is received, but before A's shadow state is merged back, the random numbers for B will be identical to the ones for A. Please note that the time window is very small for this scenario. To prevent that there is even a theoretical chance for thread A and B having the same DRBG state, the current time stamp is provided as additional information string for each new request. The addition of the time stamp as additional information string implies that now all generate functions must be capable to process a linked list with additional information strings instead of a scalar. CC: Rafael Aquini <aquini@redhat.com> Signed-off-by: Stephan Mueller <smueller@chronox.de> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Showing 2 changed files with 36 additions and 25 deletions Side-by-side Diff
crypto/drbg.c
... | ... | @@ -646,7 +646,7 @@ |
646 | 646 | /* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ |
647 | 647 | static int drbg_ctr_generate(struct drbg_state *drbg, |
648 | 648 | unsigned char *buf, unsigned int buflen, |
649 | - struct drbg_string *addtl) | |
649 | + struct list_head *addtl) | |
650 | 650 | { |
651 | 651 | int len = 0; |
652 | 652 | int ret = 0; |
... | ... | @@ -656,11 +656,8 @@ |
656 | 656 | memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); |
657 | 657 | |
658 | 658 | /* 10.2.1.5.2 step 2 */ |
659 | - if (addtl && 0 < addtl->len) { | |
660 | - LIST_HEAD(addtllist); | |
661 | - | |
662 | - list_add_tail(&addtl->list, &addtllist); | |
663 | - ret = drbg_ctr_update(drbg, &addtllist, 2); | |
659 | + if (addtl && !list_empty(addtl)) { | |
660 | + ret = drbg_ctr_update(drbg, addtl, 2); | |
664 | 661 | if (ret) |
665 | 662 | return 0; |
666 | 663 | } |
... | ... | @@ -777,7 +774,7 @@ |
777 | 774 | static int drbg_hmac_generate(struct drbg_state *drbg, |
778 | 775 | unsigned char *buf, |
779 | 776 | unsigned int buflen, |
780 | - struct drbg_string *addtl) | |
777 | + struct list_head *addtl) | |
781 | 778 | { |
782 | 779 | int len = 0; |
783 | 780 | int ret = 0; |
... | ... | @@ -785,11 +782,8 @@ |
785 | 782 | LIST_HEAD(datalist); |
786 | 783 | |
787 | 784 | /* 10.1.2.5 step 2 */ |
788 | - if (addtl && 0 < addtl->len) { | |
789 | - LIST_HEAD(addtllist); | |
790 | - | |
791 | - list_add_tail(&addtl->list, &addtllist); | |
792 | - ret = drbg_hmac_update(drbg, &addtllist, 1); | |
785 | + if (addtl && !list_empty(addtl)) { | |
786 | + ret = drbg_hmac_update(drbg, addtl, 1); | |
793 | 787 | if (ret) |
794 | 788 | return ret; |
795 | 789 | } |
796 | 790 | |
... | ... | @@ -813,14 +807,10 @@ |
813 | 807 | } |
814 | 808 | |
815 | 809 | /* 10.1.2.5 step 6 */ |
816 | - if (addtl && 0 < addtl->len) { | |
817 | - LIST_HEAD(addtllist); | |
818 | - | |
819 | - list_add_tail(&addtl->list, &addtllist); | |
820 | - ret = drbg_hmac_update(drbg, &addtllist, 1); | |
821 | - } else { | |
810 | + if (addtl && !list_empty(addtl)) | |
811 | + ret = drbg_hmac_update(drbg, addtl, 1); | |
812 | + else | |
822 | 813 | ret = drbg_hmac_update(drbg, NULL, 1); |
823 | - } | |
824 | 814 | if (ret) |
825 | 815 | return ret; |
826 | 816 | |
... | ... | @@ -944,7 +934,7 @@ |
944 | 934 | |
945 | 935 | /* processing of additional information string for Hash DRBG */ |
946 | 936 | static int drbg_hash_process_addtl(struct drbg_state *drbg, |
947 | - struct drbg_string *addtl) | |
937 | + struct list_head *addtl) | |
948 | 938 | { |
949 | 939 | int ret = 0; |
950 | 940 | struct drbg_string data1, data2; |
... | ... | @@ -955,7 +945,7 @@ |
955 | 945 | memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); |
956 | 946 | |
957 | 947 | /* 10.1.1.4 step 2 */ |
958 | - if (!addtl || 0 == addtl->len) | |
948 | + if (!addtl || list_empty(addtl)) | |
959 | 949 | return 0; |
960 | 950 | |
961 | 951 | /* 10.1.1.4 step 2a */ |
... | ... | @@ -963,7 +953,7 @@ |
963 | 953 | drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); |
964 | 954 | list_add_tail(&data1.list, &datalist); |
965 | 955 | list_add_tail(&data2.list, &datalist); |
966 | - list_add_tail(&addtl->list, &datalist); | |
956 | + list_splice_tail(addtl, &datalist); | |
967 | 957 | ret = drbg_kcapi_hash(drbg, NULL, drbg->scratchpad, &datalist); |
968 | 958 | if (ret) |
969 | 959 | goto out; |
... | ... | @@ -1029,7 +1019,7 @@ |
1029 | 1019 | /* generate function for Hash DRBG as defined in 10.1.1.4 */ |
1030 | 1020 | static int drbg_hash_generate(struct drbg_state *drbg, |
1031 | 1021 | unsigned char *buf, unsigned int buflen, |
1032 | - struct drbg_string *addtl) | |
1022 | + struct list_head *addtl) | |
1033 | 1023 | { |
1034 | 1024 | int len = 0; |
1035 | 1025 | int ret = 0; |
... | ... | @@ -1347,6 +1337,12 @@ |
1347 | 1337 | { |
1348 | 1338 | int len = 0; |
1349 | 1339 | struct drbg_state *shadow = NULL; |
1340 | + LIST_HEAD(addtllist); | |
1341 | + struct drbg_string timestamp; | |
1342 | + union { | |
1343 | + cycles_t cycles; | |
1344 | + unsigned char char_cycles[sizeof(cycles_t)]; | |
1345 | + } now; | |
1350 | 1346 | |
1351 | 1347 | if (0 == buflen || !buf) { |
1352 | 1348 | pr_devel("DRBG: no output buffer provided\n"); |
1353 | 1349 | |
... | ... | @@ -1407,8 +1403,23 @@ |
1407 | 1403 | /* 9.3.1 step 7.4 */ |
1408 | 1404 | addtl = NULL; |
1409 | 1405 | } |
1406 | + | |
1407 | + /* | |
1408 | + * Mix the time stamp into the DRBG state if the DRBG is not in | |
1409 | + * test mode. If there are two callers invoking the DRBG at the same | |
1410 | + * time, i.e. before the first caller merges its shadow state back, | |
1411 | + * both callers would obtain the same random number stream without | |
1412 | + * changing the state here. | |
1413 | + */ | |
1414 | + if (!drbg->test_data) { | |
1415 | + now.cycles = random_get_entropy(); | |
1416 | + drbg_string_fill(×tamp, now.char_cycles, sizeof(cycles_t)); | |
1417 | + list_add_tail(×tamp.list, &addtllist); | |
1418 | + } | |
1419 | + if (addtl && 0 < addtl->len) | |
1420 | + list_add_tail(&addtl->list, &addtllist); | |
1410 | 1421 | /* 9.3.1 step 8 and 10 */ |
1411 | - len = shadow->d_ops->generate(shadow, buf, buflen, addtl); | |
1422 | + len = shadow->d_ops->generate(shadow, buf, buflen, &addtllist); | |
1412 | 1423 | |
1413 | 1424 | /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ |
1414 | 1425 | shadow->reseed_ctr++; |
include/crypto/drbg.h
... | ... | @@ -102,7 +102,7 @@ |
102 | 102 | int reseed); |
103 | 103 | int (*generate)(struct drbg_state *drbg, |
104 | 104 | unsigned char *buf, unsigned int buflen, |
105 | - struct drbg_string *addtl); | |
105 | + struct list_head *addtl); | |
106 | 106 | int (*crypto_init)(struct drbg_state *drbg); |
107 | 107 | int (*crypto_fini)(struct drbg_state *drbg); |
108 | 108 |