diff --git a/src/PolarSSL++/PublicKey.cpp b/src/PolarSSL++/PublicKey.cpp index 49794a0c8..dae026082 100644 --- a/src/PolarSSL++/PublicKey.cpp +++ b/src/PolarSSL++/PublicKey.cpp @@ -10,15 +10,44 @@ -cPublicKey::cPublicKey(const AString & a_PublicKeyDER) +cPublicKey::cPublicKey(void) { pk_init(&m_Pk); - if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0) + m_CtrDrbg.Initialize("rsa_pubkey", 10); +} + + + + + +cPublicKey::cPublicKey(const AString & a_PublicKeyData) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_pubkey", 10); + int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size()); + if (res != 0) { + LOGWARNING("Failed to parse public key: -0x%x", res); + ASSERT(!"Cannot parse PubKey"); + return; + } +} + + + + + +cPublicKey::cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password) +{ + pk_init(&m_Pk); + m_CtrDrbg.Initialize("rsa_privkey", 11); + int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password); + if (res != 0) + { + LOGWARNING("Failed to parse private key: -0x%x", res); ASSERT(!"Cannot parse PubKey"); return; } - m_CtrDrbg.Initialize("rsa_pubkey", 10); } @@ -36,6 +65,8 @@ cPublicKey::~cPublicKey() int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength) { + ASSERT(IsValid()); + size_t DecryptedLen = a_DecryptedMaxLength; int res = pk_decrypt(&m_Pk, a_EncryptedData, a_EncryptedLength, @@ -55,6 +86,8 @@ int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength) { + ASSERT(IsValid()); + size_t EncryptedLength = a_EncryptedMaxLength; int res = pk_encrypt(&m_Pk, a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength, @@ -71,3 +104,46 @@ int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a + +int cPublicKey::ParsePublic(const void * a_Data, size_t a_NumBytes) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes); +} + + + + + + +int cPublicKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password) +{ + ASSERT(!IsValid()); // Cannot parse a second key + + if (a_Password.empty()) + { + return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0); + } + else + { + return pk_parse_key( + &m_Pk, + (const unsigned char *)a_Data, a_NumBytes, + (const unsigned char *)a_Password.c_str(), a_Password.size() + ); + } +} + + + + + +bool cPublicKey::IsValid(void) const +{ + return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE); +} + + + + diff --git a/src/PolarSSL++/PublicKey.h b/src/PolarSSL++/PublicKey.h index 5a0a57147..df52a4143 100644 --- a/src/PolarSSL++/PublicKey.h +++ b/src/PolarSSL++/PublicKey.h @@ -18,9 +18,18 @@ class cPublicKey { + friend class cSslContext; + public: - /** Constructs the public key out of the DER-encoded pubkey data */ - cPublicKey(const AString & a_PublicKeyDER); + /** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */ + cPublicKey(void); + + /** Constructs the public key out of the DER- or PEM-encoded pubkey data */ + cPublicKey(const AString & a_PublicKeyData); + + /** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password. + If a_Password is empty, no password is assumed. */ + cPublicKey(const AString & a_PrivateKeyData, const AString & a_Password); ~cPublicKey(); @@ -33,6 +42,20 @@ public: Both a_EncryptedData and a_DecryptedData must be at least bytes large. Returns the number of bytes decrypted, or negative number for error. */ int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength); + + /** Parses the specified data into a public key representation. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePublic(const void * a_Data, size_t a_NumBytes); + + /** Parses the specified data into a private key representation. + If a_Password is empty, no password is assumed. + The key can be DER- or PEM-encoded. + Returns 0 on success, PolarSSL error code on failure. */ + int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password); + + /** Returns true if the contained key is valid. */ + bool IsValid(void) const; protected: /** The public key PolarSSL representation */ @@ -40,8 +63,13 @@ protected: /** The random generator used in encryption and decryption */ cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + pk_context * GetInternal(void) { return &m_Pk; } } ; +typedef SharedPtr cPublicKeyPtr; diff --git a/src/PolarSSL++/RsaPrivateKey.h b/src/PolarSSL++/RsaPrivateKey.h index ffacde11b..4d03f27df 100644 --- a/src/PolarSSL++/RsaPrivateKey.h +++ b/src/PolarSSL++/RsaPrivateKey.h @@ -19,6 +19,8 @@ /** Encapsulates an RSA private key used in PKI cryptography */ class cRsaPrivateKey { + friend class cSslContext; + public: /** Creates a new empty object, the key is not assigned */ cRsaPrivateKey(void); @@ -51,8 +53,14 @@ protected: /** The random generator used for generating the key and encryption / decryption */ cCtrDrbgContext m_CtrDrbg; + + + /** Returns the internal context ptr. Only use in PolarSSL API calls. */ + rsa_context * GetInternal(void) { return &m_Rsa; } } ; +typedef SharedPtr cRsaPrivateKeyPtr; + diff --git a/src/PolarSSL++/SslContext.cpp b/src/PolarSSL++/SslContext.cpp index 1994cf844..3d2b8cef7 100644 --- a/src/PolarSSL++/SslContext.cpp +++ b/src/PolarSSL++/SslContext.cpp @@ -40,7 +40,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & if (m_IsValid) { LOGWARNING("SSL: Double initialization is not supported."); - return POLARSSL_ERR_SSL_MALLOC_FAILED; // There is no return value well-suited for this, reuse this one. + return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one. } // Set the CtrDrbg context, create a new one if needed: @@ -80,8 +80,56 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr & +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal()); +} + + + + + +void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey) +{ + ASSERT(m_IsValid); // Call Initialize() first + + // Check that both the cert and the key is valid: + if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL)) + { + LOGWARNING("SSL: Own certificate is not valid, skipping the set."); + return; + } + + // Make sure we have the cert stored for later, PolarSSL only uses the cert later on + m_OwnCert = a_OwnCert; + m_OwnCertPrivKey2 = a_OwnCertPrivKey; + + // Set into the context: + ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal()); +} + + + + + void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName) { + ASSERT(m_IsValid); // Call Initialize() first + // Store the data in our internal buffers, to avoid losing the pointers later on // PolarSSL will need these after this call returns, and the caller may move / delete the data before that: m_ExpectedPeerName = a_ExpectedPeerName; diff --git a/src/PolarSSL++/SslContext.h b/src/PolarSSL++/SslContext.h index 85add5f8b..273939b9f 100644 --- a/src/PolarSSL++/SslContext.h +++ b/src/PolarSSL++/SslContext.h @@ -11,6 +11,8 @@ #include "polarssl/ssl.h" #include "../ByteBuffer.h" +#include "PublicKey.h" +#include "RsaPrivateKey.h" #include "X509Cert.h" @@ -47,7 +49,16 @@ public: /** Returns true if the object has been initialized properly. */ bool IsValid(void) const { return m_IsValid; } - /** Sets a cert chain as the trusted cert store for this context. + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey); + + /** Sets the certificate to use as our own. Must be used when representing a server, optional when client. + Must be called after Initialize(). + Despite the class name, a_OwnCertPrivKey is a PRIVATE key. */ + void SetOwnCert(const cX509CertPtr & a_OwnCert, const cPublicKeyPtr & a_OwnCertPrivKey); + + /** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize(). Calling this will switch the context into strict cert verification mode. a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert, if it is different, the verification will fail. An empty string will disable the CN check. */ @@ -93,6 +104,15 @@ protected: /** The SSL context that PolarSSL uses. */ ssl_context m_Ssl; + /** The certificate that we present to the peer. */ + cX509CertPtr m_OwnCert; + + /** Private key for m_OwnCert, if initialized from a cRsaPrivateKey */ + cRsaPrivateKeyPtr m_OwnCertPrivKey; + + /** Private key for m_OwnCert, if initialized from a cPublicKey. Despite the class name, this is a PRIVATE key. */ + cPublicKeyPtr m_OwnCertPrivKey2; + /** True if the SSL handshake has been completed. */ bool m_HasHandshaken;