• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1'use strict';
2
3const {
4  ObjectSetPrototypeOf,
5} = primordials;
6
7const {
8  ERR_CRYPTO_SIGN_KEY_REQUIRED,
9  ERR_INVALID_ARG_TYPE,
10  ERR_INVALID_OPT_VALUE
11} = require('internal/errors').codes;
12const { validateEncoding, validateString } = require('internal/validators');
13const {
14  Sign: _Sign,
15  Verify: _Verify,
16  kSigEncDER,
17  kSigEncP1363,
18  signOneShot: _signOneShot,
19  verifyOneShot: _verifyOneShot
20} = internalBinding('crypto');
21const {
22  getDefaultEncoding,
23  kHandle,
24  getArrayBufferView,
25} = require('internal/crypto/util');
26const {
27  preparePrivateKey,
28  preparePublicOrPrivateKey
29} = require('internal/crypto/keys');
30const { Writable } = require('stream');
31const { isArrayBufferView } = require('internal/util/types');
32
33function Sign(algorithm, options) {
34  if (!(this instanceof Sign))
35    return new Sign(algorithm, options);
36  validateString(algorithm, 'algorithm');
37  this[kHandle] = new _Sign();
38  this[kHandle].init(algorithm);
39
40  Writable.call(this, options);
41}
42
43ObjectSetPrototypeOf(Sign.prototype, Writable.prototype);
44ObjectSetPrototypeOf(Sign, Writable);
45
46Sign.prototype._write = function _write(chunk, encoding, callback) {
47  this.update(chunk, encoding);
48  callback();
49};
50
51Sign.prototype.update = function update(data, encoding) {
52  encoding = encoding || getDefaultEncoding();
53
54  if (typeof data === 'string') {
55    validateEncoding(data, encoding);
56  } else if (!isArrayBufferView(data)) {
57    throw new ERR_INVALID_ARG_TYPE(
58      'data', ['string', 'Buffer', 'TypedArray', 'DataView'], data);
59  }
60
61  this[kHandle].update(data, encoding);
62  return this;
63};
64
65function getPadding(options) {
66  return getIntOption('padding', options);
67}
68
69function getSaltLength(options) {
70  return getIntOption('saltLength', options);
71}
72
73function getDSASignatureEncoding(options) {
74  if (typeof options === 'object') {
75    const { dsaEncoding = 'der' } = options;
76    if (dsaEncoding === 'der')
77      return kSigEncDER;
78    else if (dsaEncoding === 'ieee-p1363')
79      return kSigEncP1363;
80    throw new ERR_INVALID_OPT_VALUE('dsaEncoding', dsaEncoding);
81  }
82
83  return kSigEncDER;
84}
85
86function getIntOption(name, options) {
87  const value = options[name];
88  if (value !== undefined) {
89    if (value === value >> 0) {
90      return value;
91    }
92    throw new ERR_INVALID_OPT_VALUE(name, value);
93  }
94  return undefined;
95}
96
97Sign.prototype.sign = function sign(options, encoding) {
98  if (!options)
99    throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
100
101  const { data, format, type, passphrase } = preparePrivateKey(options, true);
102
103  // Options specific to RSA
104  const rsaPadding = getPadding(options);
105  const pssSaltLength = getSaltLength(options);
106
107  // Options specific to (EC)DSA
108  const dsaSigEnc = getDSASignatureEncoding(options);
109
110  const ret = this[kHandle].sign(data, format, type, passphrase, rsaPadding,
111                                 pssSaltLength, dsaSigEnc);
112
113  encoding = encoding || getDefaultEncoding();
114  if (encoding && encoding !== 'buffer')
115    return ret.toString(encoding);
116
117  return ret;
118};
119
120function signOneShot(algorithm, data, key) {
121  if (algorithm != null)
122    validateString(algorithm, 'algorithm');
123
124  if (!isArrayBufferView(data)) {
125    throw new ERR_INVALID_ARG_TYPE(
126      'data',
127      ['Buffer', 'TypedArray', 'DataView'],
128      data
129    );
130  }
131
132  if (!key)
133    throw new ERR_CRYPTO_SIGN_KEY_REQUIRED();
134
135  const {
136    data: keyData,
137    format: keyFormat,
138    type: keyType,
139    passphrase: keyPassphrase
140  } = preparePrivateKey(key);
141
142  // Options specific to RSA
143  const rsaPadding = getPadding(key);
144  const pssSaltLength = getSaltLength(key);
145
146  // Options specific to (EC)DSA
147  const dsaSigEnc = getDSASignatureEncoding(key);
148
149  return _signOneShot(keyData, keyFormat, keyType, keyPassphrase, data,
150                      algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
151}
152
153function Verify(algorithm, options) {
154  if (!(this instanceof Verify))
155    return new Verify(algorithm, options);
156  validateString(algorithm, 'algorithm');
157  this[kHandle] = new _Verify();
158  this[kHandle].init(algorithm);
159
160  Writable.call(this, options);
161}
162
163ObjectSetPrototypeOf(Verify.prototype, Writable.prototype);
164ObjectSetPrototypeOf(Verify, Writable);
165
166Verify.prototype._write = Sign.prototype._write;
167Verify.prototype.update = Sign.prototype.update;
168
169Verify.prototype.verify = function verify(options, signature, sigEncoding) {
170  const {
171    data,
172    format,
173    type,
174    passphrase
175  } = preparePublicOrPrivateKey(options, true);
176
177  sigEncoding = sigEncoding || getDefaultEncoding();
178
179  // Options specific to RSA
180  const rsaPadding = getPadding(options);
181  const pssSaltLength = getSaltLength(options);
182
183  // Options specific to (EC)DSA
184  const dsaSigEnc = getDSASignatureEncoding(options);
185
186  signature = getArrayBufferView(signature, 'signature', sigEncoding);
187
188  return this[kHandle].verify(data, format, type, passphrase, signature,
189                              rsaPadding, pssSaltLength, dsaSigEnc);
190};
191
192function verifyOneShot(algorithm, data, key, signature) {
193  if (algorithm != null)
194    validateString(algorithm, 'algorithm');
195
196  if (!isArrayBufferView(data)) {
197    throw new ERR_INVALID_ARG_TYPE(
198      'data',
199      ['Buffer', 'TypedArray', 'DataView'],
200      data
201    );
202  }
203
204  const {
205    data: keyData,
206    format: keyFormat,
207    type: keyType,
208    passphrase: keyPassphrase
209  } = preparePublicOrPrivateKey(key);
210
211  // Options specific to RSA
212  const rsaPadding = getPadding(key);
213  const pssSaltLength = getSaltLength(key);
214
215  // Options specific to (EC)DSA
216  const dsaSigEnc = getDSASignatureEncoding(key);
217
218  if (!isArrayBufferView(signature)) {
219    throw new ERR_INVALID_ARG_TYPE(
220      'signature',
221      ['Buffer', 'TypedArray', 'DataView'],
222      signature
223    );
224  }
225
226  return _verifyOneShot(keyData, keyFormat, keyType, keyPassphrase, signature,
227                        data, algorithm, rsaPadding, pssSaltLength, dsaSigEnc);
228}
229
230module.exports = {
231  Sign,
232  signOneShot,
233  Verify,
234  verifyOneShot
235};
236