diff options
author | Jeff Burdges <burdges@gnunet.org> | 2016-06-08 13:37:14 +0000 |
---|---|---|
committer | Jeff Burdges <burdges@gnunet.org> | 2016-06-08 13:37:14 +0000 |
commit | 727c093dc23c71c792261e295c3d628824bd8ccc (patch) | |
tree | 77ed6f549a83bbfe539a340c32067b6bd3765bf4 /src/util/crypto_rsa.c | |
parent | 1f33c505c42ac2b3d628b2b70b2da62e8f621a89 (diff) | |
download | gnunet-727c093dc23c71c792261e295c3d628824bd8ccc.tar.gz gnunet-727c093dc23c71c792261e295c3d628824bd8ccc.zip |
Rework the error handling for gcd(r,n) != 1 so the Taler wallet can see errors.
Diffstat (limited to 'src/util/crypto_rsa.c')
-rw-r--r-- | src/util/crypto_rsa.c | 128 |
1 files changed, 90 insertions, 38 deletions
diff --git a/src/util/crypto_rsa.c b/src/util/crypto_rsa.c index cddb87bf7..1ed9a5ce9 100644 --- a/src/util/crypto_rsa.c +++ b/src/util/crypto_rsa.c | |||
@@ -401,7 +401,7 @@ GNUNET_CRYPTO_rsa_public_key_decode (const char *buf, | |||
401 | * | 401 | * |
402 | * @param r KDF result | 402 | * @param r KDF result |
403 | * @param n RSA modulus | 403 | * @param n RSA modulus |
404 | * @return Asserts gcd(r,n) = 1 | 404 | * @return True if gcd(r,n) = 1, False means RSA key is malicious |
405 | */ | 405 | */ |
406 | static int | 406 | static int |
407 | rsa_gcd_validate(gcry_mpi_t r, gcry_mpi_t n) | 407 | rsa_gcd_validate(gcry_mpi_t r, gcry_mpi_t n) |
@@ -412,7 +412,6 @@ rsa_gcd_validate(gcry_mpi_t r, gcry_mpi_t n) | |||
412 | g = gcry_mpi_new (0); | 412 | g = gcry_mpi_new (0); |
413 | t = gcry_mpi_gcd(g,r,n); | 413 | t = gcry_mpi_gcd(g,r,n); |
414 | gcry_mpi_release (g); | 414 | gcry_mpi_release (g); |
415 | GNUNET_assert( t ); | ||
416 | return t; | 415 | return t; |
417 | } | 416 | } |
418 | 417 | ||
@@ -422,7 +421,7 @@ rsa_gcd_validate(gcry_mpi_t r, gcry_mpi_t n) | |||
422 | * | 421 | * |
423 | * @param len length of the key in bits (i.e. 2048) | 422 | * @param len length of the key in bits (i.e. 2048) |
424 | * @param bks pre-secret to use to derive the blinding key | 423 | * @param bks pre-secret to use to derive the blinding key |
425 | * @return the newly created blinding key | 424 | * @return the newly created blinding key, NULL if RSA key is malicious |
426 | */ | 425 | */ |
427 | static struct RsaBlindingKey * | 426 | static struct RsaBlindingKey * |
428 | rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, | 427 | rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, |
@@ -431,11 +430,13 @@ rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, | |||
431 | char *xts = "Blinding KDF extrator HMAC key"; /* Trusts bks' randomness more */ | 430 | char *xts = "Blinding KDF extrator HMAC key"; /* Trusts bks' randomness more */ |
432 | struct RsaBlindingKey *blind; | 431 | struct RsaBlindingKey *blind; |
433 | gcry_mpi_t n; | 432 | gcry_mpi_t n; |
434 | 433 | ||
435 | blind = GNUNET_new (struct RsaBlindingKey); | 434 | blind = GNUNET_new (struct RsaBlindingKey); |
435 | GNUNET_assert( NULL != blind ); | ||
436 | 436 | ||
437 | /* Extract the composite n from the RSA public key */ | 437 | /* Extract the composite n from the RSA public key */ |
438 | GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") ); | 438 | GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") ); |
439 | /* Assert that it at least looks like an RSA key */ | ||
439 | GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) ); | 440 | GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) ); |
440 | 441 | ||
441 | GNUNET_CRYPTO_kdf_mod_mpi (&blind->r, | 442 | GNUNET_CRYPTO_kdf_mod_mpi (&blind->r, |
@@ -443,7 +444,10 @@ rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, | |||
443 | xts, strlen(xts), | 444 | xts, strlen(xts), |
444 | bks, sizeof(*bks), | 445 | bks, sizeof(*bks), |
445 | "Blinding KDF"); | 446 | "Blinding KDF"); |
446 | rsa_gcd_validate(blind->r,n); | 447 | if (0 == rsa_gcd_validate(blind->r, n)) { |
448 | GNUNET_free (blind); | ||
449 | blind = NULL; | ||
450 | } | ||
447 | 451 | ||
448 | gcry_mpi_release (n); | 452 | gcry_mpi_release (n); |
449 | return blind; | 453 | return blind; |
@@ -667,22 +671,23 @@ numeric_mpi_alloc_n_print (gcry_mpi_t v, | |||
667 | * https://eprint.iacr.org/2001/002.pdf | 671 | * https://eprint.iacr.org/2001/002.pdf |
668 | * http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf | 672 | * http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf |
669 | * | 673 | * |
670 | * @param[out] r MPI value set to the FDH | ||
671 | * @param hash initial hash of the message to sign | 674 | * @param hash initial hash of the message to sign |
672 | * @param pkey the public key of the signer | 675 | * @param pkey the public key of the signer |
673 | * @param rsize If not NULL, the number of bytes actually stored in buffer | 676 | * @param rsize If not NULL, the number of bytes actually stored in buffer |
677 | * @return MPI value set to the FDH, NULL if RSA key is malicious | ||
674 | */ | 678 | */ |
675 | static void | 679 | static gcry_mpi_t |
676 | rsa_full_domain_hash (gcry_mpi_t *r, | 680 | rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, |
677 | const struct GNUNET_HashCode *hash, | 681 | const struct GNUNET_HashCode *hash) |
678 | const struct GNUNET_CRYPTO_RsaPublicKey *pkey) | ||
679 | { | 682 | { |
680 | gcry_mpi_t n; | 683 | gcry_mpi_t r,n; |
681 | char *xts; | 684 | char *xts; |
682 | size_t xts_len; | 685 | size_t xts_len; |
686 | int ok; | ||
683 | 687 | ||
684 | /* Extract the composite n from the RSA public key */ | 688 | /* Extract the composite n from the RSA public key */ |
685 | GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") ); | 689 | GNUNET_assert( 0 == key_from_sexp (&n, pkey->sexp, "rsa", "n") ); |
690 | /* Assert that it at least looks like an RSA key */ | ||
686 | GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) ); | 691 | GNUNET_assert( 0 == gcry_mpi_get_flag(n, GCRYMPI_FLAG_OPAQUE) ); |
687 | 692 | ||
688 | /* We key with the public denomination key as a homage to RSA-PSS by * | 693 | /* We key with the public denomination key as a homage to RSA-PSS by * |
@@ -691,16 +696,19 @@ rsa_full_domain_hash (gcry_mpi_t *r, | |||
691 | * polynomial-time one-more forgary attack. Yey seeding! */ | 696 | * polynomial-time one-more forgary attack. Yey seeding! */ |
692 | xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts); | 697 | xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts); |
693 | 698 | ||
694 | GNUNET_CRYPTO_kdf_mod_mpi (r, | 699 | GNUNET_CRYPTO_kdf_mod_mpi (&r, |
695 | n, | 700 | n, |
696 | xts, xts_len, | 701 | xts, xts_len, |
697 | hash, sizeof(*hash), | 702 | hash, sizeof(*hash), |
698 | "RSA-FDA FTpsW!"); | 703 | "RSA-FDA FTpsW!"); |
699 | GNUNET_free (xts); | 704 | GNUNET_free (xts); |
700 | 705 | ||
701 | rsa_gcd_validate(*r,n); | 706 | ok = rsa_gcd_validate(r,n); |
702 | |||
703 | gcry_mpi_release (n); | 707 | gcry_mpi_release (n); |
708 | if (ok) | ||
709 | return r; | ||
710 | gcry_mpi_release (r); | ||
711 | return NULL; | ||
704 | } | 712 | } |
705 | 713 | ||
706 | 714 | ||
@@ -710,36 +718,45 @@ rsa_full_domain_hash (gcry_mpi_t *r, | |||
710 | * @param hash hash of the message to sign | 718 | * @param hash hash of the message to sign |
711 | * @param bkey the blinding key | 719 | * @param bkey the blinding key |
712 | * @param pkey the public key of the signer | 720 | * @param pkey the public key of the signer |
713 | * @param[out] buffer set to a buffer with the blinded message to be signed | 721 | * @param[out] buf set to a buffer with the blinded message to be signed |
714 | * @return number of bytes stored in @a buffer | 722 | * @param[out] buf_size number of bytes stored in @a buf |
723 | * @return GNUNET_YES if successful, GNUNET_NO if RSA key is malicious | ||
715 | */ | 724 | */ |
716 | size_t | 725 | int |
717 | GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, | 726 | GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, |
718 | const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks, | 727 | const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks, |
719 | struct GNUNET_CRYPTO_RsaPublicKey *pkey, | 728 | struct GNUNET_CRYPTO_RsaPublicKey *pkey, |
720 | char **buffer) | 729 | char **buf, size_t *buf_size) |
721 | { | 730 | { |
722 | struct RsaBlindingKey *bkey; | 731 | struct RsaBlindingKey *bkey; |
723 | gcry_mpi_t data; | 732 | gcry_mpi_t data; |
724 | gcry_mpi_t ne[2]; | 733 | gcry_mpi_t ne[2]; |
725 | gcry_mpi_t r_e; | 734 | gcry_mpi_t r_e; |
726 | gcry_mpi_t data_r_e; | 735 | gcry_mpi_t data_r_e; |
727 | size_t n; | ||
728 | int ret; | 736 | int ret; |
729 | 737 | ||
738 | GNUNET_assert (buf != NULL && buf_size != NULL); | ||
730 | ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne"); | 739 | ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne"); |
731 | if (0 != ret) | 740 | if (0 != ret) |
732 | ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne"); | 741 | ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne"); |
733 | if (0 != ret) | 742 | if (0 != ret) |
734 | { | 743 | { |
735 | GNUNET_break (0); | 744 | GNUNET_break (0); |
736 | *buffer = NULL; | 745 | *buf = NULL; |
746 | *buf_size = 0; | ||
737 | return 0; | 747 | return 0; |
738 | } | 748 | } |
739 | 749 | ||
740 | rsa_full_domain_hash (&data, hash, pkey); | 750 | data = rsa_full_domain_hash (pkey, hash); |
741 | bkey = rsa_blinding_key_derive (pkey, | 751 | if (NULL == data) |
742 | bks); | 752 | goto rsa_gcd_validate_failure; |
753 | |||
754 | bkey = rsa_blinding_key_derive (pkey, bks); | ||
755 | if (NULL == bkey) { | ||
756 | gcry_mpi_release (data); | ||
757 | goto rsa_gcd_validate_failure; | ||
758 | } | ||
759 | |||
743 | r_e = gcry_mpi_new (0); | 760 | r_e = gcry_mpi_new (0); |
744 | gcry_mpi_powm (r_e, | 761 | gcry_mpi_powm (r_e, |
745 | bkey->r, | 762 | bkey->r, |
@@ -756,9 +773,18 @@ GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, | |||
756 | gcry_mpi_release (r_e); | 773 | gcry_mpi_release (r_e); |
757 | rsa_blinding_key_free (bkey); | 774 | rsa_blinding_key_free (bkey); |
758 | 775 | ||
759 | n = numeric_mpi_alloc_n_print (data_r_e, buffer); | 776 | *buf_size = numeric_mpi_alloc_n_print (data_r_e, buf); |
760 | gcry_mpi_release (data_r_e); | 777 | gcry_mpi_release (data_r_e); |
761 | return n; | 778 | return GNUNET_YES; |
779 | |||
780 | rsa_gcd_validate_failure: | ||
781 | /* We know the RSA key is malicious here, so warn the wallet. */ | ||
782 | /* GNUNET_break_op (0); */ | ||
783 | gcry_mpi_release (ne[0]); | ||
784 | gcry_mpi_release (ne[1]); | ||
785 | *buf = NULL; | ||
786 | *buf_size = 0; | ||
787 | return GNUNET_NO; | ||
762 | } | 788 | } |
763 | 789 | ||
764 | 790 | ||
@@ -872,7 +898,7 @@ GNUNET_CRYPTO_rsa_sign_blinded (const struct GNUNET_CRYPTO_RsaPrivateKey *key, | |||
872 | * | 898 | * |
873 | * @param key private key to use for the signing | 899 | * @param key private key to use for the signing |
874 | * @param hash the hash of the message to sign | 900 | * @param hash the hash of the message to sign |
875 | * @return NULL on error, signature on success | 901 | * @return NULL on error, including a malicious RSA key, signature on success |
876 | */ | 902 | */ |
877 | struct GNUNET_CRYPTO_RsaSignature * | 903 | struct GNUNET_CRYPTO_RsaSignature * |
878 | GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key, | 904 | GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key, |
@@ -883,13 +909,14 @@ GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key, | |||
883 | struct GNUNET_CRYPTO_RsaSignature *sig; | 909 | struct GNUNET_CRYPTO_RsaSignature *sig; |
884 | 910 | ||
885 | pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key); | 911 | pkey = GNUNET_CRYPTO_rsa_private_key_get_public (key); |
886 | rsa_full_domain_hash (&v, hash, pkey); | 912 | v = rsa_full_domain_hash (pkey, hash); |
887 | GNUNET_CRYPTO_rsa_public_key_free (pkey); | 913 | GNUNET_CRYPTO_rsa_public_key_free (pkey); |
888 | 914 | if (NULL == v) /* rsa_gcd_validate failed meaning */ | |
915 | return NULL; /* our *own* RSA key is malicious. */ | ||
916 | |||
889 | sig = rsa_sign_mpi (key, v); | 917 | sig = rsa_sign_mpi (key, v); |
890 | gcry_mpi_release (v); | 918 | gcry_mpi_release (v); |
891 | return sig; | 919 | return sig; |
892 | |||
893 | } | 920 | } |
894 | 921 | ||
895 | 922 | ||
@@ -1012,7 +1039,7 @@ GNUNET_CRYPTO_rsa_public_key_dup (const struct GNUNET_CRYPTO_RsaPublicKey *key) | |||
1012 | * @param sig the signature made on the blinded signature purpose | 1039 | * @param sig the signature made on the blinded signature purpose |
1013 | * @param bks the blinding key secret used to blind the signature purpose | 1040 | * @param bks the blinding key secret used to blind the signature purpose |
1014 | * @param pkey the public key of the signer | 1041 | * @param pkey the public key of the signer |
1015 | * @return unblinded signature on success, NULL on error | 1042 | * @return unblinded signature on success, NULL if RSA key is bad or malicious. |
1016 | */ | 1043 | */ |
1017 | struct GNUNET_CRYPTO_RsaSignature * | 1044 | struct GNUNET_CRYPTO_RsaSignature * |
1018 | GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, | 1045 | GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, |
@@ -1044,8 +1071,19 @@ GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, | |||
1044 | GNUNET_break_op (0); | 1071 | GNUNET_break_op (0); |
1045 | return NULL; | 1072 | return NULL; |
1046 | } | 1073 | } |
1047 | bkey = rsa_blinding_key_derive (pkey, | 1074 | |
1048 | bks); | 1075 | bkey = rsa_blinding_key_derive (pkey, bks); |
1076 | if (NULL == bkey) | ||
1077 | { | ||
1078 | /* RSA key is malicious since rsa_gcd_validate failed here. | ||
1079 | * It should have failed during GNUNET_CRYPTO_rsa_blind too though, | ||
1080 | * so the exchange is being malicious in an unfamilair way, maybe | ||
1081 | * just trying to crash us. */ | ||
1082 | GNUNET_break_op (0); | ||
1083 | gcry_mpi_release (n); | ||
1084 | gcry_mpi_release (s); | ||
1085 | return NULL; | ||
1086 | } | ||
1049 | 1087 | ||
1050 | r_inv = gcry_mpi_new (0); | 1088 | r_inv = gcry_mpi_new (0); |
1051 | if (1 != | 1089 | if (1 != |
@@ -1053,13 +1091,16 @@ GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, | |||
1053 | bkey->r, | 1091 | bkey->r, |
1054 | n)) | 1092 | n)) |
1055 | { | 1093 | { |
1094 | /* We cannot find r mod n, so gcd(r,n) != 1, which should get * | ||
1095 | * caught above, but we handle it the same here. */ | ||
1056 | GNUNET_break_op (0); | 1096 | GNUNET_break_op (0); |
1057 | gcry_mpi_release (n); | ||
1058 | gcry_mpi_release (r_inv); | 1097 | gcry_mpi_release (r_inv); |
1059 | gcry_mpi_release (s); | ||
1060 | rsa_blinding_key_free (bkey); | 1098 | rsa_blinding_key_free (bkey); |
1099 | gcry_mpi_release (n); | ||
1100 | gcry_mpi_release (s); | ||
1061 | return NULL; | 1101 | return NULL; |
1062 | } | 1102 | } |
1103 | |||
1063 | ubsig = gcry_mpi_new (0); | 1104 | ubsig = gcry_mpi_new (0); |
1064 | gcry_mpi_mulm (ubsig, s, r_inv, n); | 1105 | gcry_mpi_mulm (ubsig, s, r_inv, n); |
1065 | gcry_mpi_release (n); | 1106 | gcry_mpi_release (n); |
@@ -1079,13 +1120,13 @@ GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, | |||
1079 | 1120 | ||
1080 | 1121 | ||
1081 | /** | 1122 | /** |
1082 | * Verify whether the given hash corresponds to the given signature and the | 1123 | * Verify whether the given hash corresponds to the given signature and |
1083 | * signature is valid with respect to the given public key. | 1124 | * the signature is valid with respect to the given public key. |
1084 | * | 1125 | * |
1085 | * @param hash hash of the message to verify to match the @a sig | 1126 | * @param hash hash of the message to verify to match the @a sig |
1086 | * @param sig signature that is being validated | 1127 | * @param sig signature that is being validated |
1087 | * @param pkey public key of the signer | 1128 | * @param pkey public key of the signer |
1088 | * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid | 1129 | * @returns #GNUNET_YES if ok, #GNUNET_NO if RSA key is malicious, #GNUNET_SYSERR if signature is invalid |
1089 | */ | 1130 | */ |
1090 | int | 1131 | int |
1091 | GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, | 1132 | GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, |
@@ -1096,7 +1137,18 @@ GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, | |||
1096 | gcry_mpi_t r; | 1137 | gcry_mpi_t r; |
1097 | int rc; | 1138 | int rc; |
1098 | 1139 | ||
1099 | rsa_full_domain_hash (&r, hash, pkey); | 1140 | r = rsa_full_domain_hash (pkey, hash); |
1141 | if (NULL == r) { | ||
1142 | GNUNET_break_op (0); | ||
1143 | /* RSA key is malicious since rsa_gcd_validate failed here. | ||
1144 | * It should have failed during GNUNET_CRYPTO_rsa_blind too though, | ||
1145 | * so the exchange is being malicious in an unfamilair way, maybe | ||
1146 | * just trying to crash us. Arguably, we've only an internal error | ||
1147 | * though because we should've detected this in our previous call | ||
1148 | * to GNUNET_CRYPTO_rsa_unblind. */ | ||
1149 | return GNUNET_NO; | ||
1150 | } | ||
1151 | |||
1100 | data = mpi_to_sexp(r); | 1152 | data = mpi_to_sexp(r); |
1101 | gcry_mpi_release (r); | 1153 | gcry_mpi_release (r); |
1102 | 1154 | ||