From aa2f35dea8b67d403003741dfa3a331d6adfcf2d Mon Sep 17 00:00:00 2001 From: Stefan Becker Date: Thu, 17 Nov 2011 08:04:22 +0200 Subject: [PATCH] nss: add RSA crypto functions --- src/core/sipe-cert-crypto-nss.c | 80 ++++++++++++++++++++++++++++++++++++++--- src/core/sipe-cert-crypto.h | 43 ++++++++++++++++++++-- src/core/sipe-certificate.c | 3 +- src/core/sipe-crypt-nss.c | 71 ++++++++++++++++++++++++++++++++++++ src/core/sipe-crypt.h | 15 ++++++++ 5 files changed, 204 insertions(+), 8 deletions(-) diff --git a/src/core/sipe-cert-crypto-nss.c b/src/core/sipe-cert-crypto-nss.c index 5418e95f..de16093b 100755 --- a/src/core/sipe-cert-crypto-nss.c +++ b/src/core/sipe-cert-crypto-nss.c @@ -48,7 +48,27 @@ struct sipe_cert_crypto { SECKEYPublicKey *public; }; +/* + * This data structure is used in two different modes + * + * a) certificate generated by the server from our Certificate Request + * + * key_pair.private - reference to client private key, don't free! + * key_pair.public - reference to client public key, don't free! + * decoded - certificate as NSS data structure, must be freed + * raw - certificate as DER encoded binary, must be freed + * length - length of DER binary + * + * b) server certificate + * + * key_pair.private - NULL + * key_pair.public - reference to server public key, must be freed! + * decoded - certificate as NSS data structure, must be freed + * raw - NULL + * length - modulus length of server public key + */ struct certificate_nss { + struct sipe_cert_crypto key_pair; CERTCertificate *decoded; guchar *raw; gsize length; @@ -201,13 +221,20 @@ void sipe_cert_crypto_destroy(gpointer certificate) { struct certificate_nss *cn = certificate; - if (cn->decoded) - CERT_DestroyCertificate(cn->decoded); - g_free(cn->raw); - g_free(cn); + if (cn) { + /* imported server certificate - mode (b) */ + if (!cn->raw && cn->key_pair.public) + SECKEY_DestroyPublicKey(cn->key_pair.public); + if (cn->decoded) + CERT_DestroyCertificate(cn->decoded); + g_free(cn->raw); + g_free(cn); + } } -gpointer sipe_cert_crypto_import(const gchar *base64) +/* generates certificate_nss in mode (a) */ +gpointer sipe_cert_crypto_decode(struct sipe_cert_crypto *ssc, + const gchar *base64) { struct certificate_nss *cn = g_new0(struct certificate_nss, 1); @@ -219,6 +246,34 @@ gpointer sipe_cert_crypto_import(const gchar *base64) return(NULL); } + cn->key_pair = *ssc; + + return(cn); +} + +/* generates certificate_nss in mode (b) */ +gpointer sipe_cert_crypto_import(const guchar *raw, + gsize length) +{ + struct certificate_nss *cn = g_new0(struct certificate_nss, 1); + + /* cn->raw not needed as this is a server certificate */ + cn->decoded = CERT_DecodeCertFromPackage((char *) raw, length); + + if (!cn->decoded) { + sipe_cert_crypto_destroy(cn); + return(NULL); + } + + cn->key_pair.public = CERT_ExtractPublicKey(cn->decoded); + + if (!cn->key_pair.public) { + sipe_cert_crypto_destroy(cn); + return(NULL); + } + + cn->length = SECKEY_PublicKeyStrength(cn->key_pair.public); + return(cn); } @@ -257,6 +312,21 @@ const guchar *sipe_cert_crypto_raw(gpointer certificate) return(((struct certificate_nss *) certificate)->raw); } +gpointer sipe_cert_crypto_public_key(gpointer certificate) +{ + return(((struct certificate_nss *) certificate)->key_pair.public); +} + +gsize sipe_cert_crypto_modulus_length(gpointer certificate) +{ + return(((struct certificate_nss *) certificate)->length); +} + +gpointer sipe_cert_crypto_private_key(gpointer certificate) +{ + return(((struct certificate_nss *) certificate)->key_pair.private); +} + /* Local Variables: mode: c diff --git a/src/core/sipe-cert-crypto.h b/src/core/sipe-cert-crypto.h index 34c4174f..ac5af645 100644 --- a/src/core/sipe-cert-crypto.h +++ b/src/core/sipe-cert-crypto.h @@ -64,17 +64,29 @@ gchar *sipe_cert_crypto_request(struct sipe_cert_crypto *ssc, * Destroy certificate (this is a @GDestroyNotify) * * @param certificate opaque pointer to backend certificate structure + * May be @c NULL */ void sipe_cert_crypto_destroy(gpointer certificate); /** - * Import a certificate from Base64 string + * Decode a client certificate from Base64 string * * @param base64 Base64 encoded DER data * * @return opaque pointer to certificate. Must be @sipe_cert_crypto_destroy()'d. */ -gpointer sipe_cert_crypto_import(const gchar *base64); +gpointer sipe_cert_crypto_decode(struct sipe_cert_crypto *ssc, + const gchar *base64); + +/** + * Import a server certificate from DER data + * + * @param raw DER data + * @param length length of DER data + * + * @return opaque pointer to certificate. Must be @sipe_cert_crypto_destroy()'d. + */ +gpointer sipe_cert_crypto_import(const guchar *raw, gsize length); /** * Check if certificate is valid until @c offset seconds from now @@ -104,3 +116,30 @@ gsize sipe_cert_crypto_raw_length(gpointer certificate); * @return pointer to DER data */ const guchar *sipe_cert_crypto_raw(gpointer certificate); + +/** + * Get public key for certificate + * + * @param certificate opaque pointer to backend certificate structure + * + * @return opaque pointer to backend public key structure + */ +gpointer sipe_cert_crypto_public_key(gpointer certificate); + +/** + * Get public key modulus length for server certificate + * + * @param certificate opaque pointer to backend certificate structure + * + * @return server public key strength + */ +gsize sipe_cert_crypto_modulus_length(gpointer certificate); + +/** + * Get private key for client certificate + * + * @param certificate opaque pointer to backend certificate structure + * + * @return opaque pointer to backend private key structure + */ +gpointer sipe_cert_crypto_private_key(gpointer certificate); diff --git a/src/core/sipe-certificate.c b/src/core/sipe-certificate.c index 52afd5e7..f03ad1b6 100644 --- a/src/core/sipe-certificate.c +++ b/src/core/sipe-certificate.c @@ -213,7 +213,8 @@ static void get_and_publish_cert(struct sipe_core_private *sipe_private, uri); if (cert_base64) { - gpointer opaque = sipe_cert_crypto_import(cert_base64); + gpointer opaque = sipe_cert_crypto_decode(sipe_private->certificate->backend, + cert_base64); SIPE_DEBUG_INFO_NOFORMAT("get_and_publish_cert: found certificate"); diff --git a/src/core/sipe-crypt-nss.c b/src/core/sipe-crypt-nss.c index db07e10a..468627eb 100755 --- a/src/core/sipe-crypt-nss.c +++ b/src/core/sipe-crypt-nss.c @@ -154,6 +154,77 @@ sipe_crypt_rc4(const guchar *key, gsize key_length, sipe_crypt(CKM_RC4, key, key_length, plaintext, plaintext_length, encrypted_text); } +gboolean +sipe_crypt_rsa_encrypt(gpointer public, gsize modulus_length, + const guchar *plaintext, + guchar *encrypted_text) +{ + SECStatus result = PK11_PubEncryptRaw(public, + encrypted_text, (guchar *) plaintext, + modulus_length, NULL); + return(result == SECSuccess); +} + +gboolean +sipe_crypt_rsa_decrypt(gpointer private, gsize modulus_length, + const guchar *encrypted_text, + guchar *plaintext) +{ + unsigned int length; + SECStatus result = PK11_PubDecryptRaw(private, + (guchar *) encrypted_text, &length, modulus_length, + plaintext, modulus_length); + return((result == SECSuccess) && (length == modulus_length)); +} + +guchar *sipe_crypt_rsa_sign(gpointer private, + const guchar *digest, gsize digest_length, + gsize *signature_length) +{ + SECItem digItem; + SECItem sigItem; + SECStatus length; + + length = PK11_SignatureLen(private); + if (length < 0) return(NULL); + + /* digest to sign (= encrypt) with private key */ + digItem.data = (guchar *) digest; + digItem.len = digest_length; + + /* signature */ + sigItem.data = g_malloc(length); + sigItem.len = length; + + length = PK11_Sign(private, &sigItem, &digItem); + if (length != SECSuccess) { + g_free(sigItem.data); + return(NULL); + } + + *signature_length = sigItem.len; + return(sigItem.data); +} + +gboolean sipe_crypt_verify_rsa(gpointer public, + const guchar *digest, gsize digest_length, + const guchar *signature, gsize signature_length) +{ + SECItem digItem; + SECItem sigItem; + + /* digest to verify against */ + digItem.data = (guchar *) digest; + digItem.len = digest_length; + + /* signature to decrypt with public key -> digest to compare */ + sigItem.data = (guchar *) signature; + sigItem.len = signature_length; + + return(PK11_Verify(public, &sigItem, &digItem, NULL) == SECSuccess); +} + + /* Stream RC4 cipher for file transfer */ gpointer sipe_crypt_ft_start(const guchar *key) diff --git a/src/core/sipe-crypt.h b/src/core/sipe-crypt.h index c1eb363b..cdab7902 100644 --- a/src/core/sipe-crypt.h +++ b/src/core/sipe-crypt.h @@ -37,6 +37,21 @@ void sipe_crypt_rc4(const guchar *key, gsize key_length, const guchar *plaintext, gsize plaintext_length, guchar *encrypted_text); +/* plaintext & encrypted_text must point to modulus_length long spaces */ +gboolean sipe_crypt_rsa_encrypt(gpointer public, gsize modulus_length, + const guchar *plaintext, + guchar *encrypted_text); +gboolean sipe_crypt_rsa_decrypt(gpointer private, gsize modulus_length, + const guchar *encrypted_text, + guchar *plaintext); +/* must be g_free'd() */ +guchar *sipe_crypt_rsa_sign(gpointer private, + const guchar *digest, gsize digest_length, + gsize *signature_length); +gboolean sipe_crypt_verify_rsa(gpointer public, + const guchar *digest, gsize digest_length, + const guchar *signature, gsize signature_length); + /* Stream RC4 cipher for file transfer */ gpointer sipe_crypt_ft_start(const guchar *key); void sipe_crypt_ft_stream(gpointer context, -- 2.11.4.GIT