1
1
#include " openssl/rsa.h"
2
2
#include " openssl/sha.h"
3
3
#include < iostream>
4
+ #include < optional>
4
5
#include < span>
6
+ #include < vector>
5
7
6
8
#include " crypto-algorithm.h"
7
9
#include " crypto-key-rsa-components.h"
@@ -52,49 +54,47 @@ const EVP_MD *createDigestAlgorithm(JSContext *cx, JS::HandleObject key) {
52
54
}
53
55
// This implements https://w3c.github.io/webcrypto/#sha-operations for all
54
56
// the SHA algorithms that we support.
55
- std::optional<std::span <uint8_t >> rawDigest (JSContext *cx, std::span<uint8_t > data,
56
- const EVP_MD *algorithm, size_t buffer_size) {
57
+ std::optional<std::vector <uint8_t >> rawDigest (JSContext *cx, std::span<uint8_t > data,
58
+ const EVP_MD *algorithm, size_t buffer_size) {
57
59
unsigned int size;
58
- auto buf = static_cast <unsigned char *>(JS_malloc (cx, buffer_size));
59
- if (!buf) {
60
- JS_ReportOutOfMemory (cx);
61
- return std::nullopt;
62
- }
63
- if (!EVP_Digest (data.data (), data.size (), buf, &size, algorithm, NULL )) {
60
+ std::vector<uint8_t > buf (buffer_size, 0 );
61
+ if (!EVP_Digest (data.data (), data.size (), buf.data (), &size, algorithm, NULL )) {
64
62
// 2. If performing the operation results in an error, then throw an OperationError.
65
63
// TODO: Change to an OperationError DOMException
66
64
JS_ReportErrorUTF8 (cx, " SubtleCrypto.digest: failed to create digest" );
67
- JS_free (cx, buf);
68
65
return std::nullopt;
69
66
}
70
- return std::span< uint8_t > (buf, size) ;
67
+ return { std::move (buf)} ;
71
68
};
72
69
73
70
// This implements https://w3c.github.io/webcrypto/#sha-operations for all
74
71
// the SHA algorithms that we support.
75
72
JSObject *digest (JSContext *cx, std::span<uint8_t > data, const EVP_MD *algorithm,
76
73
size_t buffer_size) {
77
74
unsigned int size;
78
- auto buf = static_cast <unsigned char *>(JS_malloc (cx, buffer_size));
75
+ mozilla::UniquePtr<uint8_t [], JS::FreePolicy> buf{
76
+ static_cast <uint8_t *>(JS_malloc (cx, buffer_size))};
79
77
if (!buf) {
80
78
JS_ReportOutOfMemory (cx);
81
79
return nullptr ;
82
80
}
83
- if (!EVP_Digest (data.data (), data.size (), buf, &size, algorithm, NULL )) {
81
+ if (!EVP_Digest (data.data (), data.size (), buf. get () , &size, algorithm, NULL )) {
84
82
// 2. If performing the operation results in an error, then throw an OperationError.
85
83
// TODO: Change to an OperationError DOMException
86
84
JS_ReportErrorUTF8 (cx, " SubtleCrypto.digest: failed to create digest" );
87
- JS_free (cx, buf);
88
85
return nullptr ;
89
86
}
90
87
// 3. Return a new ArrayBuffer containing result.
91
88
JS::RootedObject array_buffer (cx);
92
- array_buffer.set (JS::NewArrayBufferWithContents (cx, size, buf));
89
+ array_buffer.set (JS::NewArrayBufferWithContents (cx, size, buf. get () ));
93
90
if (!array_buffer) {
94
- JS_free (cx, buf);
95
91
JS_ReportOutOfMemory (cx);
96
92
return nullptr ;
97
93
}
94
+
95
+ // `array_buffer` now owns `buf`
96
+ static_cast <void >(buf.release ());
97
+
98
98
return array_buffer;
99
99
};
100
100
@@ -603,13 +603,12 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify::sign(JSContext *cx, JS::
603
603
return nullptr ;
604
604
}
605
605
606
- auto digestOption = ::builtins::rawDigest (cx, data, algorithm, EVP_MD_size (algorithm));
607
- if (!digestOption .has_value ()) {
606
+ auto digest = ::builtins::rawDigest (cx, data, algorithm, EVP_MD_size (algorithm));
607
+ if (!digest .has_value ()) {
608
608
// TODO Rename error to OperationError
609
609
JS_ReportErrorLatin1 (cx, " OperationError" );
610
610
return nullptr ;
611
611
}
612
- auto digest = digestOption.value ();
613
612
614
613
// 2. Perform the signature generation operation defined in Section 8.2 of [RFC3447] with the
615
614
// key represented by the [[handle]] internal slot of key as the signer's private key and the
@@ -643,24 +642,23 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify::sign(JSContext *cx, JS::
643
642
}
644
643
645
644
size_t signature_length;
646
- if (EVP_PKEY_sign (ctx, nullptr , &signature_length, digest. data (), digest. size ()) <= 0 ) {
645
+ if (EVP_PKEY_sign (ctx, nullptr , &signature_length, digest-> data (), digest-> size ()) <= 0 ) {
647
646
// TODO Rename error to OperationError
648
647
JS_ReportErrorLatin1 (cx, " OperationError" );
649
648
return nullptr ;
650
649
}
651
650
652
651
// 4. Let signature be the value S that results from performing the operation.
653
- uint8_t *signature = reinterpret_cast <uint8_t *>(JS_malloc (cx, signature_length));
654
- if (EVP_PKEY_sign (ctx, signature, &signature_length, digest. data (), digest. size ()) <= 0 ) {
652
+ mozilla::UniquePtr< uint8_t [], JS::FreePolicy> signature{ static_cast <uint8_t *>(JS_malloc (cx, signature_length))} ;
653
+ if (EVP_PKEY_sign (ctx, signature. get () , &signature_length, digest-> data (), digest-> size ()) <= 0 ) {
655
654
// TODO Rename error to OperationError
656
655
JS_ReportErrorLatin1 (cx, " OperationError" );
657
- JS_free (cx, signature);
658
656
return nullptr ;
659
657
}
660
658
661
659
// 5. Return a new ArrayBuffer associated with the relevant global object of this [HTML], and
662
660
// containing the bytes of signature.
663
- JS::RootedObject buffer (cx, JS::NewArrayBufferWithContents (cx, signature_length, signature));
661
+ JS::RootedObject buffer (cx, JS::NewArrayBufferWithContents (cx, signature_length, signature. get () ));
664
662
if (!buffer) {
665
663
// We can be here is the array buffer was too large -- if that was the case then a
666
664
// JSMSG_BAD_ARRAY_LENGTH will have been created. No other failure scenarios in this path will
@@ -669,9 +667,12 @@ JSObject *CryptoAlgorithmRSASSA_PKCS1_v1_5_Sign_Verify::sign(JSContext *cx, JS::
669
667
// TODO Rename error to InternalError
670
668
JS_ReportErrorLatin1 (cx, " InternalError" );
671
669
}
672
- JS_free (cx, signature);
673
670
return nullptr ;
674
671
}
672
+
673
+ // `signature` is now owned by `buffer`
674
+ static_cast <void >(signature.release ());
675
+
675
676
return buffer;
676
677
}
677
678
@@ -1033,4 +1034,4 @@ JSObject *CryptoAlgorithmSHA512::digest(JSContext *cx, std::span<uint8_t> data)
1033
1034
return ::builtins::digest (cx, data, EVP_sha512 (), SHA512_DIGEST_LENGTH);
1034
1035
}
1035
1036
1036
- } // namespace builtins
1037
+ } // namespace builtins
0 commit comments