Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / crypto / ec_private_key_openssl.cc
index 8504ab5..2d44759 100644 (file)
@@ -12,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "crypto/openssl_util.h"
+#include "crypto/scoped_openssl_types.h"
 
 namespace crypto {
 
@@ -24,6 +25,10 @@ namespace {
 //       style guide, hence the unusual parameter placement / types.
 typedef int (*ExportBioFunction)(BIO* bio, const void* key);
 
+typedef ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
+    ScopedPKCS8_PRIV_KEY_INFO;
+typedef ScopedOpenSSL<X509_SIG, X509_SIG_free>::Type ScopedX509_SIG;
+
 // Helper to export |key| into |output| via the specified ExportBioFunction.
 bool ExportKeyWithBio(const void* key,
                       ExportBioFunction export_fn,
@@ -31,7 +36,7 @@ bool ExportKeyWithBio(const void* key,
   if (!key)
     return false;
 
-  ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem()));
+  ScopedBIO bio(BIO_new(BIO_s_mem()));
   if (!bio.get())
     return false;
 
@@ -87,8 +92,7 @@ bool ECPrivateKey::IsSupported() { return true; }
 ECPrivateKey* ECPrivateKey::Create() {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
 
-  ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(
-      EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+  ScopedEC_KEY ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
   if (!ec_key.get() || !EC_KEY_generate_key(ec_key.get()))
     return NULL;
 
@@ -97,6 +101,7 @@ ECPrivateKey* ECPrivateKey::Create() {
   if (!result->key_ || !EVP_PKEY_set1_EC_KEY(result->key_, ec_key.get()))
     return NULL;
 
+  CHECK_EQ(EVP_PKEY_EC, EVP_PKEY_type(result->key_->type));
   return result.release();
 }
 
@@ -112,38 +117,37 @@ ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
     return NULL;
 
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
-  // Write the encrypted private key into a memory BIO.
-  char* private_key_data = reinterpret_cast<char*>(
-      const_cast<uint8*>(&encrypted_private_key_info[0]));
-  int private_key_data_len =
-      static_cast<int>(encrypted_private_key_info.size());
-  ScopedOpenSSL<BIO, BIO_free_all> bio(
-      BIO_new_mem_buf(private_key_data, private_key_data_len));
-  if (!bio.get())
-    return NULL;
 
-  // Convert it, then decrypt it into a PKCS#8 object.
-  ScopedOpenSSL<X509_SIG, X509_SIG_free> p8_encrypted(
-      d2i_PKCS8_bio(bio.get(), NULL));
-  if (!p8_encrypted.get())
+  const uint8_t* data = &encrypted_private_key_info[0];
+  const uint8_t* ptr = data;
+  ScopedX509_SIG p8_encrypted(
+      d2i_X509_SIG(NULL, &ptr, encrypted_private_key_info.size()));
+  if (!p8_encrypted || ptr != data + encrypted_private_key_info.size())
     return NULL;
 
-  ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8_decrypted(
-      PKCS8_decrypt(p8_encrypted.get(),
-                    password.c_str(),
-                    static_cast<int>(password.size())));
-  if (!p8_decrypted.get() && password.empty()) {
-    // Hack for reading keys generated by ec_private_key_nss. Passing NULL
-    // causes OpenSSL to use an empty password instead of "\0\0".
-    p8_decrypted.reset(PKCS8_decrypt(p8_encrypted.get(), NULL, 0));
+  ScopedPKCS8_PRIV_KEY_INFO p8_decrypted;
+  if (password.empty()) {
+    // Hack for reading keys generated by an older version of the OpenSSL
+    // code. OpenSSL used to use "\0\0" rather than the empty string because it
+    // would treat the password as an ASCII string to be converted to UCS-2
+    // while NSS used a byte string.
+    p8_decrypted.reset(PKCS8_decrypt_pbe(
+        p8_encrypted.get(), reinterpret_cast<const uint8_t*>("\0\0"), 2));
+  }
+  if (!p8_decrypted) {
+    p8_decrypted.reset(PKCS8_decrypt_pbe(
+        p8_encrypted.get(),
+        reinterpret_cast<const uint8_t*>(password.data()),
+        password.size()));
   }
-  if (!p8_decrypted.get())
+
+  if (!p8_decrypted)
     return NULL;
 
   // Create a new EVP_PKEY for it.
   scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
   result->key_ = EVP_PKCS82PKEY(p8_decrypted.get());
-  if (!result->key_)
+  if (!result->key_ || EVP_PKEY_type(result->key_->type) != EVP_PKEY_EC)
     return NULL;
 
   return result.release();
@@ -155,8 +159,7 @@ bool ECPrivateKey::ExportEncryptedPrivateKey(
     std::vector<uint8>* output) {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
   // Convert into a PKCS#8 object.
-  ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> pkcs8(
-      EVP_PKEY2PKCS8(key_));
+  ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(key_));
   if (!pkcs8.get())
     return false;
 
@@ -164,15 +167,14 @@ bool ECPrivateKey::ExportEncryptedPrivateKey(
   // NOTE: NSS uses SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC
   // so use NID_pbe_WithSHA1And3_Key_TripleDES_CBC which should be the OpenSSL
   // equivalent.
-  ScopedOpenSSL<X509_SIG, X509_SIG_free> encrypted(
-      PKCS8_encrypt(NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
-                    NULL,
-                    password.c_str(),
-                    static_cast<int>(password.size()),
-                    NULL,
-                    0,
-                    iterations,
-                    pkcs8.get()));
+  ScopedX509_SIG encrypted(PKCS8_encrypt_pbe(
+      NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
+      reinterpret_cast<const uint8_t*>(password.data()),
+      password.size(),
+      NULL,
+      0,
+      iterations,
+      pkcs8.get()));
   if (!encrypted.get())
     return false;
 
@@ -188,9 +190,29 @@ bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
       key_, reinterpret_cast<ExportBioFunction>(i2d_PUBKEY_bio), output);
 }
 
+bool ECPrivateKey::ExportRawPublicKey(std::string* output) {
+  // i2d_PublicKey will produce an ANSI X9.62 public key which, for a P-256
+  // key, is 0x04 (meaning uncompressed) followed by the x and y field
+  // elements as 32-byte, big-endian numbers.
+  static const int kExpectedKeyLength = 65;
+
+  int len = i2d_PublicKey(key_, NULL);
+  if (len != kExpectedKeyLength)
+    return false;
+
+  uint8 buf[kExpectedKeyLength];
+  uint8* derp = buf;
+  len = i2d_PublicKey(key_, &derp);
+  if (len != kExpectedKeyLength)
+    return false;
+
+  output->assign(reinterpret_cast<char*>(buf + 1), kExpectedKeyLength - 1);
+  return true;
+}
+
 bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
-  ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_));
+  ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
   return ExportKey(ec_key.get(),
                    reinterpret_cast<ExportDataFunction>(i2d_ECPrivateKey),
                    output);
@@ -198,7 +220,7 @@ bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
 
 bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
   OpenSSLErrStackTracer err_tracer(FROM_HERE);
-  ScopedOpenSSL<EC_KEY, EC_KEY_free> ec_key(EVP_PKEY_get1_EC_KEY(key_));
+  ScopedEC_KEY ec_key(EVP_PKEY_get1_EC_KEY(key_));
   return ExportKey(ec_key.get(),
                    reinterpret_cast<ExportDataFunction>(i2d_ECParameters),
                    output);