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