@@ -233,6 +233,57 @@ const data = Buffer.from('hello store');
233233 { code : 'ERR_CRYPTO_INVALID_JWK' } ) ;
234234}
235235
236+ {
237+ // Read the URI from the URL's private state. Public accessors on a branded
238+ // subclass must not redirect a previously created URL to a different key.
239+ const trustedHref = pathToFileURL (
240+ path . join ( tmpdir . path , 'priv.pem' ) ) . href ;
241+ const redirectHref = pathToFileURL (
242+ path . join ( tmpdir . path , 'rsa.pem' ) ) . href ;
243+ class RedirectingURL extends URL {
244+ get href ( ) { return redirectHref ; }
245+ }
246+ const subclassURL = new RedirectingURL ( trustedHref ) ;
247+ assert . strictEqual (
248+ URL . prototype . toString . call ( subclassURL ) , trustedHref ) ;
249+ assert . strictEqual (
250+ createPrivateKey ( subclassURL ) . asymmetricKeyType , 'ed25519' ) ;
251+
252+ // The same applies when the accessor is replaced on URL.prototype.
253+ const prototypeURL = new URL ( trustedHref ) ;
254+ const hrefDescriptor = Object . getOwnPropertyDescriptor ( URL . prototype , 'href' ) ;
255+ try {
256+ Object . defineProperty ( URL . prototype , 'href' , {
257+ ...hrefDescriptor ,
258+ get ( ) { return redirectHref ; } ,
259+ } ) ;
260+ assert . strictEqual (
261+ URL . prototype . toString . call ( prototypeURL ) , trustedHref ) ;
262+ assert . strictEqual (
263+ createPrivateKey ( prototypeURL ) . asymmetricKeyType , 'ed25519' ) ;
264+ } finally {
265+ Object . defineProperty ( URL . prototype , 'href' , hrefDescriptor ) ;
266+ }
267+
268+ // Replacing `protocol` must not turn an opaque STORE URI into a file path.
269+ const filePathname = pathToFileURL (
270+ path . join ( tmpdir . path , 'priv.pem' ) ) . pathname ;
271+ const opaqueURL = new URL ( `pkcs11:${ filePathname } ` ) ;
272+ const protocolDescriptor = Object . getOwnPropertyDescriptor (
273+ URL . prototype , 'protocol' ) ;
274+ try {
275+ Object . defineProperty ( URL . prototype , 'protocol' , {
276+ ...protocolDescriptor ,
277+ get ( ) { return 'file:' ; } ,
278+ } ) ;
279+ assert . throws ( ( ) => createPrivateKey ( opaqueURL ) , {
280+ code : 'ERR_OSSL_OSSL_STORE_UNSUPPORTED' ,
281+ } ) ;
282+ } finally {
283+ Object . defineProperty ( URL . prototype , 'protocol' , protocolDescriptor ) ;
284+ }
285+ }
286+
236287{
237288 // The URI is handed to OpenSSL as a NUL-terminated C string, so an embedded
238289 // NUL must be rejected rather than silently truncating the path.
0 commit comments