1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef mozilla_dom_CryptoKey_h
8 #define mozilla_dom_CryptoKey_h
9 
10 #include "nsCycleCollectionParticipant.h"
11 #include "nsWrapperCache.h"
12 #include "nsIGlobalObject.h"
13 #include "pk11pub.h"
14 #include "keyhi.h"
15 #include "ScopedNSSTypes.h"
16 #include "mozilla/ErrorResult.h"
17 #include "mozilla/dom/CryptoBuffer.h"
18 #include "mozilla/dom/KeyAlgorithmProxy.h"
19 #include "js/StructuredClone.h"
20 #include "js/TypeDecls.h"
21 
22 #define CRYPTOKEY_SC_VERSION 0x00000001
23 
24 class nsIGlobalObject;
25 
26 namespace mozilla {
27 namespace dom {
28 
29 /*
30 
31 The internal structure of keys is dictated by the need for cloning.
32 We store everything besides the key data itself in a 32-bit bitmask,
33 with the following structure (byte-aligned for simplicity, in order
34 from least to most significant):
35 
36 Bits  Usage
37 0     Extractable
38 1-7   [reserved]
39 8-15  KeyType
40 16-23 KeyUsage
41 24-31 [reserved]
42 
43 In the order of a hex value for a uint32_t
44 
45    3                   2                   1                   0
46  1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
47 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 |~~~~~~~~~~~~~~~|     Usage     |     Type      |~~~~~~~~~~~~~|E|
49 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50 
51 Thus, internally, a key has the following fields:
52 * uint32_t - flags for extractable, usage, type
53 * KeyAlgorithm - the algorithm (which must serialize/deserialize itself)
54 * The actual keys (which the CryptoKey must serialize)
55 
56 */
57 
58 struct JsonWebKey;
59 
60 class CryptoKey final : public nsISupports, public nsWrapperCache {
61  public:
62   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
63   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CryptoKey)
64 
65   static const uint32_t CLEAR_EXTRACTABLE = 0xFFFFFFE;
66   static const uint32_t EXTRACTABLE = 0x00000001;
67 
68   static const uint32_t CLEAR_TYPE = 0xFFFF00FF;
69   static const uint32_t TYPE_MASK = 0x0000FF00;
70   enum KeyType {
71     UNKNOWN = 0x00000000,
72     SECRET = 0x00000100,
73     PUBLIC = 0x00000200,
74     PRIVATE = 0x00000300
75   };
76 
77   static const uint32_t CLEAR_USAGES = 0xFF00FFFF;
78   static const uint32_t USAGES_MASK = 0x00FF0000;
79   enum KeyUsage {
80     ENCRYPT = 0x00010000,
81     DECRYPT = 0x00020000,
82     SIGN = 0x00040000,
83     VERIFY = 0x00080000,
84     DERIVEKEY = 0x00100000,
85     DERIVEBITS = 0x00200000,
86     WRAPKEY = 0x00400000,
87     UNWRAPKEY = 0x00800000
88   };
89 
90   explicit CryptoKey(nsIGlobalObject* aWindow);
91 
GetParentObject()92   nsIGlobalObject* GetParentObject() const { return mGlobal; }
93 
94   virtual JSObject* WrapObject(JSContext* aCx,
95                                JS::Handle<JSObject*> aGivenProto) override;
96 
97   // WebIDL methods
98   void GetType(nsString& aRetVal) const;
99   bool Extractable() const;
100   void GetAlgorithm(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal,
101                     ErrorResult& aRv) const;
102   void GetUsages(nsTArray<nsString>& aRetVal) const;
103 
104   // The below methods are not exposed to JS, but C++ can use
105   // them to manipulate the object
106 
107   KeyAlgorithmProxy& Algorithm();
108   const KeyAlgorithmProxy& Algorithm() const;
109   KeyType GetKeyType() const;
110   nsresult SetType(const nsString& aType);
111   void SetType(KeyType aType);
112   void SetExtractable(bool aExtractable);
113   nsresult AddPublicKeyData(SECKEYPublicKey* point);
114   void ClearUsages();
115   nsresult AddUsage(const nsString& aUsage);
116   nsresult AddUsageIntersecting(const nsString& aUsage, uint32_t aUsageMask);
117   void AddUsage(KeyUsage aUsage);
118   bool HasAnyUsage();
119   bool HasUsage(KeyUsage aUsage);
120   bool HasUsageOtherThan(uint32_t aUsages);
121   static bool IsRecognizedUsage(const nsString& aUsage);
122   static bool AllUsagesRecognized(const Sequence<nsString>& aUsages);
123 
124   nsresult SetSymKey(const CryptoBuffer& aSymKey);
125   nsresult SetPrivateKey(SECKEYPrivateKey* aPrivateKey);
126   nsresult SetPublicKey(SECKEYPublicKey* aPublicKey);
127 
128   // Accessors for the keys themselves
129   const CryptoBuffer& GetSymKey() const;
130   UniqueSECKEYPrivateKey GetPrivateKey() const;
131   UniqueSECKEYPublicKey GetPublicKey() const;
132 
133   // Serialization and deserialization convenience methods
134   // Note:
135   // 1. The inputs aKeyData are non-const only because the NSS import
136   //    functions lack the const modifier.  They should not be modified.
137   // 2. All of the NSS key objects returned need to be freed by the caller.
138   static UniqueSECKEYPrivateKey PrivateKeyFromPkcs8(CryptoBuffer& aKeyData);
139   static nsresult PrivateKeyToPkcs8(SECKEYPrivateKey* aPrivKey,
140                                     CryptoBuffer& aRetVal);
141 
142   static UniqueSECKEYPublicKey PublicKeyFromSpki(CryptoBuffer& aKeyData);
143   static nsresult PublicKeyToSpki(SECKEYPublicKey* aPubKey,
144                                   CryptoBuffer& aRetVal);
145 
146   static UniqueSECKEYPrivateKey PrivateKeyFromJwk(const JsonWebKey& aJwk);
147   static nsresult PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
148                                   JsonWebKey& aRetVal);
149 
150   static UniqueSECKEYPublicKey PublicKeyFromJwk(const JsonWebKey& aKeyData);
151   static nsresult PublicKeyToJwk(SECKEYPublicKey* aPubKey, JsonWebKey& aRetVal);
152 
153   static UniqueSECKEYPublicKey PublicDhKeyFromRaw(
154       CryptoBuffer& aKeyData, const CryptoBuffer& aPrime,
155       const CryptoBuffer& aGenerator);
156   static nsresult PublicDhKeyToRaw(SECKEYPublicKey* aPubKey,
157                                    CryptoBuffer& aRetVal);
158 
159   static UniqueSECKEYPublicKey PublicECKeyFromRaw(CryptoBuffer& aKeyData,
160                                                   const nsString& aNamedCurve);
161   static nsresult PublicECKeyToRaw(SECKEYPublicKey* aPubKey,
162                                    CryptoBuffer& aRetVal);
163 
164   static bool PublicKeyValid(SECKEYPublicKey* aPubKey);
165 
166   // Structured clone methods use these to clone keys
167   bool WriteStructuredClone(JSStructuredCloneWriter* aWriter) const;
168   bool ReadStructuredClone(JSStructuredCloneReader* aReader);
169 
170  private:
~CryptoKey()171   ~CryptoKey() {}
172 
173   RefPtr<nsIGlobalObject> mGlobal;
174   uint32_t mAttributes;  // see above
175   KeyAlgorithmProxy mAlgorithm;
176 
177   // Only one key handle should be set, according to the KeyType
178   CryptoBuffer mSymKey;
179   UniqueSECKEYPrivateKey mPrivateKey;
180   UniqueSECKEYPublicKey mPublicKey;
181 };
182 
183 }  // namespace dom
184 }  // namespace mozilla
185 
186 #endif  // mozilla_dom_CryptoKey_h
187