Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / chrome / renderer / resources / extensions / enterprise_platform_keys / subtle_crypto.js
blob017a3e26d7f06a1fa036fcfaa7b5194f54085c19
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 var utils = require('utils');
6 var internalAPI = require('enterprise.platformKeys.internalAPI');
7 var intersect = require('enterprise.platformKeys.utils').intersect;
8 var KeyPair = require('enterprise.platformKeys.KeyPair').KeyPair;
9 var keyModule = require('enterprise.platformKeys.Key');
10 var getSpki = keyModule.getSpki;
11 var KeyUsage = keyModule.KeyUsage;
13 var normalizeAlgorithm =
14 requireNative('enterprise_platform_keys_natives').NormalizeAlgorithm;
16 // This error is thrown by the internal and public API's token functions and
17 // must be rethrown by this custom binding. Keep this in sync with the C++ part
18 // of this API.
19 var errorInvalidToken = "The token is not valid.";
21 // The following errors are specified in WebCrypto.
22 // TODO(pneubeck): These should be DOMExceptions.
23 function CreateNotSupportedError() {
24 return new Error('The algorithm is not supported');
27 function CreateInvalidAccessError() {
28 return new Error('The requested operation is not valid for the provided key');
31 function CreateDataError() {
32 return new Error('Data provided to an operation does not meet requirements');
35 function CreateSyntaxError() {
36 return new Error('A required parameter was missing or out-of-range');
39 function CreateOperationError() {
40 return new Error('The operation failed for an operation-specific reason');
43 // Catches an |internalErrorInvalidToken|. If so, forwards it to |reject| and
44 // returns true.
45 function catchInvalidTokenError(reject) {
46 if (chrome.runtime.lastError &&
47 chrome.runtime.lastError.message == errorInvalidToken) {
48 reject(chrome.runtime.lastError);
49 return true;
51 return false;
54 // Returns true if |array| is a BigInteger describing the standard public
55 // exponent 65537. In particular, it ignores leading zeros as required by the
56 // BigInteger definition in WebCrypto.
57 function equalsStandardPublicExponent(array) {
58 var expected = [0x01, 0x00, 0x01];
59 if (array.length < expected.length)
60 return false;
61 for (var i = 0; i < array.length; i++) {
62 var expectedDigit = 0;
63 if (i < expected.length) {
64 // |expected| is symmetric, endianness doesn't matter.
65 expectedDigit = expected[i];
67 if (array[array.length - 1 - i] !== expectedDigit)
68 return false;
70 return true;
73 /**
74 * Implementation of WebCrypto.SubtleCrypto used in enterprise.platformKeys.
75 * @param {string} tokenId The id of the backing Token.
76 * @constructor
78 var SubtleCryptoImpl = function(tokenId) {
79 this.tokenId = tokenId;
82 SubtleCryptoImpl.prototype.generateKey =
83 function(algorithm, extractable, keyUsages) {
84 var subtleCrypto = this;
85 return new Promise(function(resolve, reject) {
86 // TODO(pneubeck): Apply the algorithm normalization of the WebCrypto
87 // implementation.
89 if (extractable) {
90 // Note: This deviates from WebCrypto.SubtleCrypto.
91 throw CreateNotSupportedError();
93 if (intersect(keyUsages, [KeyUsage.sign, KeyUsage.verify]).length !=
94 keyUsages.length) {
95 throw CreateDataError();
97 var normalizedAlgorithmParameters =
98 normalizeAlgorithm(algorithm, 'GenerateKey');
99 if (!normalizedAlgorithmParameters) {
100 // TODO(pneubeck): It's not clear from the WebCrypto spec which error to
101 // throw here.
102 throw CreateSyntaxError();
105 // normalizeAlgorithm returns an array, but publicExponent should be a
106 // Uint8Array.
107 normalizedAlgorithmParameters.publicExponent =
108 new Uint8Array(normalizedAlgorithmParameters.publicExponent);
110 if (normalizedAlgorithmParameters.name !== 'RSASSA-PKCS1-v1_5' ||
111 !equalsStandardPublicExponent(
112 normalizedAlgorithmParameters.publicExponent)) {
113 // Note: This deviates from WebCrypto.SubtleCrypto.
114 throw CreateNotSupportedError();
117 internalAPI.generateKey(subtleCrypto.tokenId,
118 normalizedAlgorithmParameters.modulusLength,
119 function(spki) {
120 if (catchInvalidTokenError(reject))
121 return;
122 if (chrome.runtime.lastError) {
123 reject(CreateOperationError());
124 return;
126 resolve(new KeyPair(spki, normalizedAlgorithmParameters, keyUsages));
131 SubtleCryptoImpl.prototype.sign = function(algorithm, key, dataView) {
132 var subtleCrypto = this;
133 return new Promise(function(resolve, reject) {
134 if (key.type != 'private' || key.usages.indexOf(KeyUsage.sign) == -1)
135 throw CreateInvalidAccessError();
137 var normalizedAlgorithmParameters =
138 normalizeAlgorithm(algorithm, 'Sign');
139 if (!normalizedAlgorithmParameters) {
140 // TODO(pneubeck): It's not clear from the WebCrypto spec which error to
141 // throw here.
142 throw CreateSyntaxError();
145 // Create an ArrayBuffer that equals the dataView. Note that dataView.buffer
146 // might contain more data than dataView.
147 var data = dataView.buffer.slice(dataView.byteOffset,
148 dataView.byteOffset + dataView.byteLength);
149 internalAPI.sign(subtleCrypto.tokenId,
150 getSpki(key),
151 key.algorithm.hash.name,
152 data,
153 function(signature) {
154 if (catchInvalidTokenError(reject))
155 return;
156 if (chrome.runtime.lastError) {
157 reject(CreateOperationError());
158 return;
160 resolve(signature);
165 SubtleCryptoImpl.prototype.exportKey = function(format, key) {
166 return new Promise(function(resolve, reject) {
167 if (format == 'pkcs8') {
168 // Either key.type is not 'private' or the key is not extractable. In both
169 // cases the error is the same.
170 throw CreateInvalidAccessError();
171 } else if (format == 'spki') {
172 if (key.type != 'public')
173 throw CreateInvalidAccessError();
174 resolve(getSpki(key));
175 } else {
176 // TODO(pneubeck): It should be possible to export to format 'jwk'.
177 throw CreateNotSupportedError();
182 exports.SubtleCrypto =
183 utils.expose('SubtleCrypto',
184 SubtleCryptoImpl,
185 {functions:['generateKey', 'sign', 'exportKey']});