summaryrefslogtreecommitdiff
path: root/lib/gnutls_pk.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gnutls_pk.c')
-rw-r--r--lib/gnutls_pk.c329
1 files changed, 294 insertions, 35 deletions
diff --git a/lib/gnutls_pk.c b/lib/gnutls_pk.c
index a906547917..a7a27cb80f 100644
--- a/lib/gnutls_pk.c
+++ b/lib/gnutls_pk.c
@@ -29,13 +29,17 @@
#include <gnutls_datum.h>
#include "debug.h"
+static int _gnutls_pk_sign(int algo, MPI* data, MPI hash, MPI ** pkey);
+static int _gnutls_pk_verify(int algo, MPI hash, MPI** data, MPI **pkey);
+
/* Do PKCS-1 RSA encryption.
* pkey is the public key and n the modulus.
*/
-int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
- MPI pkey, MPI n, int btype)
+int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext,
+ gnutls_datum plaintext, MPI pkey, MPI n,
+ int btype)
{
int k, psize, i, ret;
MPI m, res;
@@ -64,30 +68,30 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
psize = k - 3 - plaintext.size;
ps = &edata[2];
- switch(btype) {
- case 2:
+ switch (btype) {
+ case 2:
_gnutls_get_random(ps, psize, GNUTLS_WEAK_RANDOM);
for (i = 0; i < psize; i++) {
if (ps[i] == 0)
ps[i] = 0xff;
}
break;
- case 1:
+ case 1:
for (i = 0; i < psize; i++)
ps[i] = 0xff;
- break;
+ break;
#ifdef ALLOW_BLOCK_0
- case 0:
+ case 0:
for (i = 0; i < psize; i++) {
ps[i] = 0x00;
}
- break;
+ break;
#endif
- default:
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_ERROR;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_ERROR;
}
-
+
ps[psize] = 0;
memcpy(&ps[psize + 1], plaintext.data, plaintext.size);
@@ -108,7 +112,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
return ret;
}
- _gnutls_mpi_print( NULL, &psize, res);
+ _gnutls_mpi_print(NULL, &psize, res);
ciphertext->data = gnutls_malloc(psize);
if (ciphertext->data == NULL) {
@@ -116,7 +120,7 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
_gnutls_mpi_release(&res);
return GNUTLS_E_MEMORY_ERROR;
}
- _gnutls_mpi_print( ciphertext->data, &psize, res);
+ _gnutls_mpi_print(ciphertext->data, &psize, res);
ciphertext->size = psize;
_gnutls_mpi_release(&res);
@@ -129,8 +133,9 @@ int _gnutls_pkcs1_rsa_encrypt(gnutls_datum * ciphertext, gnutls_datum plaintext,
* pkey is the private key and n the modulus.
* Can decrypt block type 1 and type packets.
*/
-int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext,
- MPI pkey, MPI n, int btype)
+int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext,
+ gnutls_datum ciphertext, MPI pkey, MPI n,
+ int btype)
{
int k, esize, i, ret;
MPI c, res;
@@ -162,14 +167,14 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext
return ret;
}
- _gnutls_mpi_print( NULL, &esize, res);
- edata = gnutls_malloc(esize+1);
+ _gnutls_mpi_print(NULL, &esize, res);
+ edata = gnutls_malloc(esize + 1);
if (edata == NULL) {
gnutls_assert();
_gnutls_mpi_release(&res);
return GNUTLS_E_MEMORY_ERROR;
}
- _gnutls_mpi_print( &edata[1], &esize, res);
+ _gnutls_mpi_print(&edata[1], &esize, res);
_gnutls_mpi_release(&res);
@@ -188,8 +193,8 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext
}
ret = GNUTLS_E_DECRYPTION_FAILED;
- switch(btype) {
- case 2:
+ switch (btype) {
+ case 2:
for (i = 2; i < esize; i++) {
if (edata[i] == 0) {
ret = 0;
@@ -197,7 +202,7 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext
}
}
break;
- case 1:
+ case 1:
for (i = 2; i < esize; i++) {
if (edata[i] == 0 && i > 2) {
ret = 0;
@@ -208,30 +213,144 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext
break;
}
}
- break;
- default:
- gnutls_assert();
- return GNUTLS_E_UNKNOWN_ERROR;
+ break;
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_ERROR;
}
i++;
-
+
if (ret < 0) {
gnutls_assert();
gnutls_free(edata);
return GNUTLS_E_DECRYPTION_FAILED;
}
-
- if (gnutls_sset_datum( plaintext, &edata[i], esize - i) < 0) {
+
+ if (gnutls_sset_datum(plaintext, &edata[i], esize - i) < 0) {
gnutls_assert();
gnutls_free(edata);
return GNUTLS_E_MEMORY_ERROR;
}
-
+
gnutls_free(edata);
return 0;
}
+
+int _gnutls_rsa_verify( const gnutls_datum* vdata, const gnutls_datum *ciphertext,
+ MPI pkey, MPI n, int btype) {
+
+ gnutls_datum plain;
+ int ret;
+
+ /* decrypt signature */
+ if ( (ret=_gnutls_pkcs1_rsa_decrypt( &plain, *ciphertext, pkey, n, btype)) < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if (plain.size != vdata->size) {
+ gnutls_assert();
+ gnutls_sfree_datum( &plain);
+ return GNUTLS_E_PK_SIGNATURE_FAILED;
+ }
+
+ if ( memcmp(plain.data, vdata->data, plain.size)!=0) {
+ gnutls_assert();
+ gnutls_sfree_datum( &plain);
+ return GNUTLS_E_PK_SIGNATURE_FAILED;
+ }
+
+ gnutls_sfree_datum( &plain);
+
+ return 0; /* ok */
+}
+
+
+/* Do DSA signature calculation
+ */
+int _gnutls_dsa_sign(gnutls_datum * signature, gnutls_datum plaintext,
+ MPI p, MPI q, MPI g, MPI y)
+{
+ MPI res[2], mdata;
+ int sig_size;
+ MPI *_pkey[DSA_PARAMS];
+ int k, ret, psize;
+
+ k = plaintext.size;
+ if (_gnutls_mpi_scan(&mdata, plaintext.data, &k) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ _pkey[0] = &p;
+ _pkey[1] = &q;
+ _pkey[2] = &g;
+ _pkey[3] = &y;
+ ret = _gnutls_pk_sign(GCRY_PK_DSA, res, mdata, _pkey);
+ /* res now holds r,s */
+ _gnutls_mpi_release(&mdata);
+
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+#error FIX r,s
+
+ _gnutls_mpi_print(NULL, &sig_size, res[0]);
+
+ signature->data = gnutls_malloc(sig_size);
+ if (signature->data == NULL) {
+ gnutls_assert();
+ _gnutls_mpi_release(&res[0]);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+ _gnutls_mpi_print(signature->data, &psize, res[0]);
+ signature->size = psize;
+
+ _gnutls_mpi_release(&res[0]);
+
+ return 0;
+}
+
+int _gnutls_dsa_verify( const gnutls_datum* vdata, const gnutls_datum *ciphertext,
+ MPI p, MPI q, MPI g, MPI y) {
+
+ MPI mdata;
+ int ret, k;
+ MPI *_pkey[DSA_PARAMS];
+ MPI *_data[2];
+ MPI r, s;
+
+ #error FIX r,s
+
+ k = vdata->size;
+ if (_gnutls_mpi_scan(&mdata, vdata->data, &k) != 0) {
+ gnutls_assert();
+ return GNUTLS_E_MPI_SCAN_FAILED;
+ }
+
+ /* decrypt signature */
+ _pkey[0] = &p;
+ _pkey[1] = &q;
+ _pkey[2] = &g;
+ _pkey[3] = &y;
+
+ _data[0] = &r;
+ _data[1] = &s;
+ if ( (ret=_gnutls_pk_verify( GCRY_PK_DSA, mdata, _data, _pkey)) < 0) {
+ _gnutls_mpi_release(&mdata);
+ gnutls_assert();
+ return ret;
+ }
+ _gnutls_mpi_release(&mdata);
+
+ return 0; /* ok */
+}
+
+
/* this is taken from gnupg
*/
@@ -239,17 +358,20 @@ int _gnutls_pkcs1_rsa_decrypt(gnutls_sdatum * plaintext, gnutls_datum ciphertext
* Emulate our old PK interface here - sometime in the future we might
* change the internal design to directly fit to libgcrypt.
*/
-int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey)
+int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI ** pkey)
{
GCRY_SEXP s_ciph, s_data, s_pkey;
int rc;
/* make a sexp from pkey */
- if (algo == GCRY_PK_RSA) {
+ switch (algo) {
+ case GCRY_PK_RSA:
rc = gcry_sexp_build(&s_pkey, NULL,
"(public-key(rsa(n%m)(e%m)))",
*pkey[0], *pkey[1]);
- } else {
+ break;
+
+ default:
gnutls_assert();
return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
}
@@ -272,8 +394,8 @@ int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey)
if (rc != 0) {
gnutls_assert();
- return GNUTLS_E_UNKNOWN_ERROR;
-
+ return GNUTLS_E_PK_ENCRYPTION_FAILED;
+
} else { /* add better error handling or make gnupg use S-Exp directly */
GCRY_SEXP list = gcry_sexp_find_token(s_ciph, "a", 0);
if (list == NULL) {
@@ -295,3 +417,140 @@ int _gnutls_pk_encrypt(int algo, MPI * resarr, MPI data, MPI **pkey)
gcry_sexp_release(s_ciph);
return rc;
}
+
+/* in case of DSA puts into data, r,s
+ */
+static
+int _gnutls_pk_sign(int algo, MPI* data, MPI hash, MPI ** pkey)
+{
+ GCRY_SEXP s_hash, s_key, s_sig;
+ int rc;
+
+ /* make a sexp from pkey */
+ switch (algo) {
+ case GCRY_PK_DSA:
+ rc = gcry_sexp_build(&s_key, NULL,
+ "(public-key(rsa(p%m)(q%m)(g%m)(y%m)(x%m)))",
+ *pkey[0], *pkey[1], *pkey[2],
+ *pkey[3], *pkey[4]);
+ break;
+
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
+ }
+
+ if (rc != 0) {
+ gnutls_assert();
+ return GNUTLS_E_INTERNAL;
+ }
+
+ /* put the data into a simple list */
+ if (gcry_sexp_build(&s_hash, NULL, "%m", hash)) {
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_ERROR;
+ }
+
+ /* pass it to libgcrypt */
+ rc = gcry_pk_sign(&s_sig, s_hash, s_key);
+ gcry_sexp_release(s_hash);
+ gcry_sexp_release(s_key);
+
+ if (rc != 0) {
+ gnutls_assert();
+ return GNUTLS_E_PK_ENCRYPTION_FAILED;
+
+ } else {
+ GCRY_SEXP list = gcry_sexp_find_token( s_sig, "r" , 0);
+ if (list == NULL) {
+ gnutls_assert();
+ gcry_sexp_release(s_sig);
+ return GNUTLS_E_INTERNAL;
+ }
+
+ data[0] = gcry_sexp_nth_mpi( list, 1, 0 );
+ gcry_sexp_release (list);
+
+ list = gcry_sexp_find_token( s_sig, "s" , 0);
+ if (list == NULL) {
+ gnutls_assert();
+ gcry_sexp_release(s_sig);
+ return GNUTLS_E_INTERNAL;
+ }
+
+ data[1] = gcry_sexp_nth_mpi( list, 1, 0 );
+ gcry_sexp_release (list);
+
+ }
+
+ gcry_sexp_release(s_sig);
+ return 0;
+}
+
+
+static int _gnutls_pk_verify(int algo, MPI hash, MPI** data, MPI **pkey)
+{
+ GCRY_SEXP s_sig, s_hash, s_pkey;
+ int rc;
+
+ /* make a sexp from pkey */
+ switch (algo) {
+ case GCRY_PK_DSA:
+ rc = gcry_sexp_build(&s_pkey, NULL,
+ "(public-key(dsa(p%m)(q%m)(g%m)(y%m)))",
+ pkey[0], pkey[1], pkey[2],
+ pkey[3]);
+ break;
+
+ default:
+ gnutls_assert();
+ return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
+ }
+
+ if (rc != 0) {
+ gnutls_assert();
+ gcry_sexp_release(s_pkey);
+ return GNUTLS_E_INTERNAL;
+ }
+
+ /* put the data into a simple list */
+ if (gcry_sexp_build(&s_hash, NULL, "%m", hash)) {
+ gnutls_assert();
+ gcry_sexp_release(s_pkey);
+ return GNUTLS_E_UNKNOWN_ERROR;
+ }
+
+ switch (algo) {
+ case GCRY_PK_DSA:
+ rc = gcry_sexp_build(&s_sig, NULL,
+ "(sig-val(dsa(r%m)(s%m)))",
+ *data[0], *data[1]);
+ break;
+
+ default:
+ gnutls_assert();
+ gcry_sexp_release(s_pkey);
+ gcry_sexp_release(s_sig);
+ return GNUTLS_E_UNKNOWN_KX_ALGORITHM;
+ }
+
+ if (rc != 0) {
+ gnutls_assert();
+ gcry_sexp_release(s_pkey);
+ gcry_sexp_release(s_sig);
+ return GNUTLS_E_INTERNAL;
+ }
+
+ rc = gcry_pk_verify( s_sig, s_hash, s_pkey );
+
+ gcry_sexp_release(s_sig);
+ gcry_sexp_release(s_hash);
+ gcry_sexp_release(s_pkey);
+
+ if (rc != 0) {
+ gnutls_assert();
+ return GNUTLS_E_PK_SIGNATURE_FAILED;
+ }
+
+ return 0;
+}