@@ -12,10 +12,16 @@ import {
1212 SecretKeyObject ,
1313} from "ext:deno_node/internal/crypto/keys.ts" ;
1414import {
15+ ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS ,
16+ ERR_CRYPTO_INVALID_DIGEST ,
17+ ERR_CRYPTO_UNKNOWN_CIPHER ,
18+ ERR_CRYPTO_UNKNOWN_DH_GROUP ,
1519 ERR_INCOMPATIBLE_OPTION_PAIR ,
1620 ERR_INVALID_ARG_VALUE ,
1721 ERR_MISSING_OPTION ,
1822} from "ext:deno_node/internal/errors.ts" ;
23+ import { getCiphers } from "ext:deno_node/internal/crypto/util.ts" ;
24+ import { getHashes } from "ext:deno_node/internal/crypto/hash.ts" ;
1925import {
2026 validateBuffer ,
2127 validateFunction ,
@@ -578,6 +584,8 @@ export function generateKeyPair(
578584 callback = options ;
579585 options = undefined ;
580586 }
587+ validateFunction ( callback , "callback" ) ;
588+
581589 _generateKeyPair ( type , options )
582590 . then (
583591 ( res ) => callback ! ( null , res . publicKey , res . privateKey ) ,
@@ -819,9 +827,188 @@ export function generateKeyPairSync(
819827const kSync = 0 ;
820828const kAsync = 1 ;
821829
830+ function parseKeyFormat (
831+ formatStr : string | undefined ,
832+ defaultFormat : string | undefined ,
833+ optionName : string ,
834+ ) : string | undefined {
835+ if ( formatStr === undefined && defaultFormat !== undefined ) {
836+ return defaultFormat ;
837+ } else if ( formatStr === "pem" ) {
838+ return "pem" ;
839+ } else if ( formatStr === "der" ) {
840+ return "der" ;
841+ } else if ( formatStr === "jwk" ) {
842+ return "jwk" ;
843+ }
844+ throw new ERR_INVALID_ARG_VALUE ( optionName , formatStr ) ;
845+ }
846+
847+ function parseKeyType (
848+ typeStr : string | undefined ,
849+ required : boolean ,
850+ keyType : string | undefined ,
851+ isPublic : boolean | undefined ,
852+ optionName : string ,
853+ ) : string | undefined {
854+ if ( typeStr === undefined && ! required ) {
855+ return undefined ;
856+ } else if ( typeStr === "pkcs1" ) {
857+ if ( keyType !== undefined && keyType !== "rsa" ) {
858+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS (
859+ typeStr ,
860+ "can only be used for RSA keys" ,
861+ ) ;
862+ }
863+ return "pkcs1" ;
864+ } else if ( typeStr === "spki" && isPublic !== false ) {
865+ return "spki" ;
866+ } else if ( typeStr === "pkcs8" && isPublic !== true ) {
867+ return "pkcs8" ;
868+ } else if ( typeStr === "sec1" && isPublic !== true ) {
869+ if ( keyType !== undefined && keyType !== "ec" ) {
870+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS (
871+ typeStr ,
872+ "can only be used for EC keys" ,
873+ ) ;
874+ }
875+ return "sec1" ;
876+ }
877+
878+ throw new ERR_INVALID_ARG_VALUE ( optionName , typeStr ) ;
879+ }
880+
881+ function option ( name : string , objName ?: string ) : string {
882+ return objName === undefined
883+ ? `options.${ name } `
884+ : `options.${ objName } .${ name } ` ;
885+ }
886+
887+ function isStringOrBuffer ( val : unknown ) : boolean {
888+ return typeof val === "string" ||
889+ ArrayBuffer . isView ( val ) ||
890+ val instanceof ArrayBuffer ||
891+ val instanceof SharedArrayBuffer ;
892+ }
893+
894+ function parseKeyFormatAndType (
895+ enc : any ,
896+ keyType : string | undefined ,
897+ isPublic : boolean | undefined ,
898+ objName ?: string ,
899+ ) {
900+ const { format : formatStr , type : typeStr } = enc ;
901+
902+ const isInput = keyType === undefined ;
903+ const format = parseKeyFormat (
904+ formatStr ,
905+ isInput ? "pem" : undefined ,
906+ option ( "format" , objName ) ,
907+ ) ;
908+
909+ const isRequired = ( ! isInput || format === "der" ) && format !== "jwk" ;
910+ const type = parseKeyType (
911+ typeStr ,
912+ isRequired ,
913+ keyType ,
914+ isPublic ,
915+ option ( "type" , objName ) ,
916+ ) ;
917+ return { format, type } ;
918+ }
919+
920+ function parsePublicKeyEncoding (
921+ enc : any ,
922+ keyType : string | undefined ,
923+ objName : string ,
924+ ) {
925+ validateObject ( enc , "options" ) ;
926+
927+ const { format, type } = parseKeyFormatAndType (
928+ enc ,
929+ keyType ,
930+ keyType ? true : undefined ,
931+ objName ,
932+ ) ;
933+
934+ return { format, type } ;
935+ }
936+
937+ function parsePrivateKeyEncoding (
938+ enc : any ,
939+ keyType : string | undefined ,
940+ objName : string ,
941+ ) {
942+ validateObject ( enc , "options" ) ;
943+
944+ const { format, type } = parseKeyFormatAndType ( enc , keyType , false , objName ) ;
945+
946+ const { cipher, passphrase } = enc ;
947+
948+ if ( cipher != null ) {
949+ if ( typeof cipher !== "string" ) {
950+ throw new ERR_INVALID_ARG_VALUE ( option ( "cipher" , objName ) , cipher ) ;
951+ }
952+ if ( ! getCiphers ( ) . includes ( cipher ) ) {
953+ throw new ERR_CRYPTO_UNKNOWN_CIPHER ( ) ;
954+ }
955+ if (
956+ format === "der" &&
957+ ( type === "pkcs1" || type === "sec1" )
958+ ) {
959+ throw new ERR_CRYPTO_INCOMPATIBLE_KEY_OPTIONS (
960+ type ,
961+ "does not support encryption" ,
962+ ) ;
963+ }
964+ } else if ( passphrase !== undefined ) {
965+ throw new ERR_INVALID_ARG_VALUE ( option ( "cipher" , objName ) , cipher ) ;
966+ }
967+
968+ if ( cipher != null && ! isStringOrBuffer ( passphrase ) ) {
969+ throw new ERR_INVALID_ARG_VALUE ( option ( "passphrase" , objName ) , passphrase ) ;
970+ }
971+
972+ return { format, type, cipher, passphrase } ;
973+ }
974+
975+ function validateKeyEncoding ( keyType : string , options : any ) {
976+ if ( options == null || typeof options !== "object" ) return ;
977+
978+ const { publicKeyEncoding, privateKeyEncoding } = options ;
979+
980+ if ( publicKeyEncoding != null ) {
981+ if ( typeof publicKeyEncoding === "object" ) {
982+ parsePublicKeyEncoding ( publicKeyEncoding , keyType , "publicKeyEncoding" ) ;
983+ } else {
984+ throw new ERR_INVALID_ARG_VALUE (
985+ "options.publicKeyEncoding" ,
986+ publicKeyEncoding ,
987+ ) ;
988+ }
989+ }
990+
991+ if ( privateKeyEncoding != null ) {
992+ if ( typeof privateKeyEncoding === "object" ) {
993+ parsePrivateKeyEncoding (
994+ privateKeyEncoding ,
995+ keyType ,
996+ "privateKeyEncoding" ,
997+ ) ;
998+ } else {
999+ throw new ERR_INVALID_ARG_VALUE (
1000+ "options.privateKeyEncoding" ,
1001+ privateKeyEncoding ,
1002+ ) ;
1003+ }
1004+ }
1005+ }
1006+
8221007function createJob ( mode , type , options ) {
8231008 validateString ( type , "type" ) ;
8241009
1010+ validateKeyEncoding ( type , options ) ;
1011+
8251012 if ( options !== undefined ) {
8261013 validateObject ( options , "options" ) ;
8271014 }
@@ -867,9 +1054,15 @@ function createJob(mode, type, options) {
8671054 }
8681055 if ( hashAlgorithm !== undefined ) {
8691056 validateString ( hashAlgorithm , "options.hashAlgorithm" ) ;
1057+ if ( ! getHashes ( ) . includes ( hashAlgorithm ) ) {
1058+ throw new ERR_CRYPTO_INVALID_DIGEST ( hashAlgorithm ) ;
1059+ }
8701060 }
8711061 if ( mgf1HashAlgorithm !== undefined ) {
8721062 validateString ( mgf1HashAlgorithm , "options.mgf1HashAlgorithm" ) ;
1063+ if ( ! getHashes ( ) . includes ( mgf1HashAlgorithm ) ) {
1064+ throw new ERR_CRYPTO_INVALID_DIGEST ( mgf1HashAlgorithm , "MGF1" ) ;
1065+ }
8731066 }
8741067 if ( hash !== undefined ) {
8751068 process . emitWarning (
@@ -995,6 +1188,13 @@ function createJob(mode, type, options) {
9951188
9961189 validateString ( group , "options.group" ) ;
9971190
1191+ if (
1192+ group !== "modp5" && group !== "modp14" && group !== "modp15" &&
1193+ group !== "modp16" && group !== "modp17" && group !== "modp18"
1194+ ) {
1195+ throw new ERR_CRYPTO_UNKNOWN_DH_GROUP ( ) ;
1196+ }
1197+
9981198 if ( mode === kSync ) {
9991199 return op_node_generate_dh_group_key ( group ) ;
10001200 } else {
0 commit comments