aboutsummaryrefslogtreecommitdiff
path: root/src/util/crypto_rsa.c
diff options
context:
space:
mode:
authorJeff Burdges <burdges@gnunet.org>2016-06-08 13:37:14 +0000
committerJeff Burdges <burdges@gnunet.org>2016-06-08 13:37:14 +0000
commit727c093dc23c71c792261e295c3d628824bd8ccc (patch)
tree77ed6f549a83bbfe539a340c32067b6bd3765bf4 /src/util/crypto_rsa.c
parent1f33c505c42ac2b3d628b2b70b2da62e8f621a89 (diff)
downloadgnunet-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.c128
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 */
406static int 406static int
407rsa_gcd_validate(gcry_mpi_t r, gcry_mpi_t n) 407rsa_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 */
427static struct RsaBlindingKey * 426static struct RsaBlindingKey *
428rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey, 427rsa_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 */
675static void 679static gcry_mpi_t
676rsa_full_domain_hash (gcry_mpi_t *r, 680rsa_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 */
716size_t 725int
717GNUNET_CRYPTO_rsa_blind (const struct GNUNET_HashCode *hash, 726GNUNET_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
780rsa_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 */
877struct GNUNET_CRYPTO_RsaSignature * 903struct GNUNET_CRYPTO_RsaSignature *
878GNUNET_CRYPTO_rsa_sign_fdh (const struct GNUNET_CRYPTO_RsaPrivateKey *key, 904GNUNET_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 */
1017struct GNUNET_CRYPTO_RsaSignature * 1044struct GNUNET_CRYPTO_RsaSignature *
1018GNUNET_CRYPTO_rsa_unblind (struct GNUNET_CRYPTO_RsaSignature *sig, 1045GNUNET_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 */
1090int 1131int
1091GNUNET_CRYPTO_rsa_verify (const struct GNUNET_HashCode *hash, 1132GNUNET_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