1bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Copyright 2013 The Chromium Authors. All rights reserved. 2bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 3bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch// found in the LICENSE file. 4bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 5bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "net/cert/jwk_serializer.h" 6bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 7bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <cert.h> 8bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <keyhi.h> 9bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include <nss.h> 10bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 11bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/base64.h" 12bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "base/values.h" 13bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "crypto/nss_util.h" 14bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch#include "crypto/scoped_nss_types.h" 15bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 16bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace net { 17bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 18bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace JwkSerializer { 19bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 20bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochnamespace { 21bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 22bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertEcPrime256v1PublicKeyInfoToJwk( 23bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch CERTSubjectPublicKeyInfo* spki, 24bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::DictionaryValue* public_key_jwk) { 25ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch static const int kUncompressedEncodingType = 4; 26bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch static const int kPrime256v1PublicKeyLength = 64; 27bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // The public key value is encoded as 0x04 + 64 bytes of public key. 28bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // NSS gives the length as the bit length. 29bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (spki->subjectPublicKey.len != (kPrime256v1PublicKeyLength + 1) * 8 || 30ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch spki->subjectPublicKey.data[0] != kUncompressedEncodingType) 31bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 32bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) public_key_jwk->SetString("kty", "EC"); 34bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public_key_jwk->SetString("crv", "P-256"); 35bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 36bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::StringPiece x( 37bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch reinterpret_cast<char*>(spki->subjectPublicKey.data + 1), 38bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch kPrime256v1PublicKeyLength / 2); 39bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch std::string x_b64; 40bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::Base64Encode(x, &x_b64); 41bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public_key_jwk->SetString("x", x_b64); 42bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 43bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::StringPiece y( 44bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch reinterpret_cast<char*>(spki->subjectPublicKey.data + 1 + 45bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch kPrime256v1PublicKeyLength / 2), 46bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch kPrime256v1PublicKeyLength / 2); 47bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch std::string y_b64; 48bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::Base64Encode(y, &y_b64); 49bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public_key_jwk->SetString("y", y_b64); 50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return true; 51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 52bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 53bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertEcPublicKeyInfoToJwk( 54bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch CERTSubjectPublicKeyInfo* spki, 55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::DictionaryValue* public_key_jwk) { 56bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // 1.2.840.10045.3.1.7 57bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // (iso.member-body.us.ansi-x9-62.ellipticCurve.primeCurve.prime256v1) 58bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // (This includes the DER-encoded type (OID) and length: parameters can be 59bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // anything, so the DER type isn't implied, and NSS includes it.) 60bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch static const unsigned char kPrime256v1[] = { 61bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 62bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch }; 63bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (spki->algorithm.parameters.len == sizeof(kPrime256v1) && 64bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch !memcmp(spki->algorithm.parameters.data, kPrime256v1, 65bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch sizeof(kPrime256v1))) { 66bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return ConvertEcPrime256v1PublicKeyInfoToJwk(spki, public_key_jwk); 67bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 68bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // TODO(juanlang): other curves 69bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 70bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 71bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)typedef scoped_ptr< 73bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch CERTSubjectPublicKeyInfo, 74bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch crypto::NSSDestroyer<CERTSubjectPublicKeyInfo, 75bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch SECKEY_DestroySubjectPublicKeyInfo> > 76bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch ScopedCERTSubjectPublicKeyInfo; 77bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 78bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} // namespace 79bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 80bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdochbool ConvertSpkiFromDerToJwk( 81bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch const base::StringPiece& spki_der, 82bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch base::DictionaryValue* public_key_jwk) { 83bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch public_key_jwk->Clear(); 84bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 85bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch crypto::EnsureNSSInit(); 86bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!NSS_IsInitialized()) 88bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 89bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 90bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch SECItem sec_item; 91bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch sec_item.data = const_cast<unsigned char*>( 92bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch reinterpret_cast<const unsigned char*>(spki_der.data())); 93bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch sec_item.len = spki_der.size(); 94bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch ScopedCERTSubjectPublicKeyInfo spki( 95bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch SECKEY_DecodeDERSubjectPublicKeyInfo(&sec_item)); 96bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (!spki) 97bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return false; 98bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 99bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // 1.2.840.10045.2 100bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // (iso.member-body.us.ansi-x9-62.id-ecPublicKey) 101bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // (This omits the ASN.1 encoding of the type (OID) and length: the fact that 102bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // this is an OID is already clear, and NSS omits it here.) 103bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch static const unsigned char kIdEcPublicKey[] = { 104bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01 105bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch }; 106bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch bool rv = false; 107bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch if (spki->algorithm.algorithm.len == sizeof(kIdEcPublicKey) && 108bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch !memcmp(spki->algorithm.algorithm.data, kIdEcPublicKey, 109bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch sizeof(kIdEcPublicKey))) { 110bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch rv = ConvertEcPublicKeyInfoToJwk(spki.get(), public_key_jwk); 111bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch } 112bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch // TODO(juanlang): other algorithms 113bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return rv; 114bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} 115bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 116bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} // namespace JwkSerializer 117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch} // namespace net 119