From 8377f7bfa35e3c5bca2f0047b32e35384004ce2c Mon Sep 17 00:00:00 2001 From: Maor Leger Date: Tue, 4 Feb 2025 09:37:43 -0800 Subject: [PATCH] [keyvault] Add warnings for usage of RSA-OAEP and RSA1_5 (#32818) ### Packages impacted by this PR @azure/keyvault-keys ### Issues associated with this PR Resolves #32636 Resolves #32751 ### Describe the problem that is addressed by this PR This PR accomplishes two goals: 1. Use generated enum names instead of overwriting them with our hand-authored ones in keyvault-keys 2. Adds a warning about using RSA1_5 and RSA-OAEP by proxy of (1) - exposing the generated enum names directly Note: APIView diff requires a fix to the parser (see https://github.com/Azure/azure-sdk-tools/issues/9768) --- sdk/keyvault/generate.ts | 42 ---------- .../keyvault-keys/samples-dev/cryptography.ts | 9 +- .../samples/v4/javascript/cryptography.js | 11 ++- .../samples/v4/typescript/src/cryptography.ts | 13 +-- .../src/cryptographyClientModels.ts | 84 +++---------------- .../keyvault-keys/src/generated/index.ts | 1 + .../src/generated/models/index.ts | 1 + .../src/generated/models/models.ts | 80 ++++++++++-------- 8 files changed, 80 insertions(+), 161 deletions(-) delete mode 100644 sdk/keyvault/generate.ts diff --git a/sdk/keyvault/generate.ts b/sdk/keyvault/generate.ts deleted file mode 100644 index c5c945790873..000000000000 --- a/sdk/keyvault/generate.ts +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env node - -const { execSync } = require("child_process"); -const fs = require("fs"); -const path = require("path"); - -// Helper to execute shell commands and log output -function execCommand(command) { - try { - execSync(command, { stdio: "inherit" }); - } catch (error) { - console.error(`Command failed: ${command}`); - process.exit(1); - } -} - -console.log("Setting up the environment..."); - -// Workaround for src-folder support in emitter: -// End state: src/generated/* contains generated code (instead of src/generated/src/*) - -// Step 1: Remove all files in src/generated/* -execCommand("rm -rf src/generated/*"); - -// Step 2: Copy tsp-location.yaml to src/generated -execCommand("cp tsp-location.yaml src/generated"); - -// Step 3: Run tsp-client command -// emitter-option as a workaround for https://github.com/Azure/azure-rest-api-specs/issues/31610 -execCommand(`tsp-client update -d -o src/generated --emitter-options generateMetadata=false`); -// execCommand( -// "tsp-client update -d -o src/generated --tsp-config ~/workspace/azure-rest-api-specs/specification/keyvault/Security.KeyVault.Keys/tspconfig.yaml --local-spec-repo ~/workspace/azure-rest-api-specs/specification/keyvault/Security.KeyVault.Keys --repo ~/workspace/azure-rest-api-specs --commit 9561bad7d2eed94cc91aa6164d3721b8aa8699fe --emitter-options generateMetadata=false" -// ); - -// Step 4: Move generated/src/* files to generated until src-folder is supported -execCommand("mv src/generated/src/* src/generated/"); - -// Step 5: Remove generated/src -execCommand("rm -rf src/generated/src"); - -// Step 6: Remove tsp-location.yaml from generated folder -execCommand("rm src/generated/tsp-location.yaml"); diff --git a/sdk/keyvault/keyvault-keys/samples-dev/cryptography.ts b/sdk/keyvault/keyvault-keys/samples-dev/cryptography.ts index 82342f276244..965d0f974725 100644 --- a/sdk/keyvault/keyvault-keys/samples-dev/cryptography.ts +++ b/sdk/keyvault/keyvault-keys/samples-dev/cryptography.ts @@ -56,14 +56,17 @@ export async function main(): Promise { }); console.log("encrypt result: ", encrypt); - const decrypt = await cryptoClient.decrypt({ algorithm: "RSA1_5", ciphertext: encrypt.result }); + const decrypt = await cryptoClient.decrypt({ + algorithm: "RSA-OAEP-256", + ciphertext: encrypt.result, + }); console.log("decrypt: ", decrypt.result.toString()); // Wrap and unwrap - const wrapped = await cryptoClient.wrapKey("RSA-OAEP", Buffer.from("My Message")); + const wrapped = await cryptoClient.wrapKey("RSA-OAEP-256", Buffer.from("My Message")); console.log("wrap result: ", wrapped); - const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP", wrapped.result); + const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP-256", wrapped.result); console.log("unwrap result: ", unwrapped); } diff --git a/sdk/keyvault/keyvault-keys/samples/v4/javascript/cryptography.js b/sdk/keyvault/keyvault-keys/samples/v4/javascript/cryptography.js index 0265c8eaf689..f6005daa66e2 100644 --- a/sdk/keyvault/keyvault-keys/samples/v4/javascript/cryptography.js +++ b/sdk/keyvault/keyvault-keys/samples/v4/javascript/cryptography.js @@ -5,7 +5,7 @@ * @summary Uses an Azure Key Vault key to sign/verify, encrypt/decrypt, and wrap/unwrap data. */ -const { createHash } = require("crypto"); +const { createHash } = require("node:crypto"); const { CryptographyClient, KeyClient } = require("@azure/keyvault-keys"); const { DefaultAzureCredential } = require("@azure/identity"); @@ -55,14 +55,17 @@ async function main() { }); console.log("encrypt result: ", encrypt); - const decrypt = await cryptoClient.decrypt({ algorithm: "RSA1_5", ciphertext: encrypt.result }); + const decrypt = await cryptoClient.decrypt({ + algorithm: "RSA-OAEP-256", + ciphertext: encrypt.result, + }); console.log("decrypt: ", decrypt.result.toString()); // Wrap and unwrap - const wrapped = await cryptoClient.wrapKey("RSA-OAEP", Buffer.from("My Message")); + const wrapped = await cryptoClient.wrapKey("RSA-OAEP-256", Buffer.from("My Message")); console.log("wrap result: ", wrapped); - const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP", wrapped.result); + const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP-256", wrapped.result); console.log("unwrap result: ", unwrapped); } diff --git a/sdk/keyvault/keyvault-keys/samples/v4/typescript/src/cryptography.ts b/sdk/keyvault/keyvault-keys/samples/v4/typescript/src/cryptography.ts index 6747098165c6..d1eb4cad6434 100644 --- a/sdk/keyvault/keyvault-keys/samples/v4/typescript/src/cryptography.ts +++ b/sdk/keyvault/keyvault-keys/samples/v4/typescript/src/cryptography.ts @@ -5,7 +5,7 @@ * @summary Uses an Azure Key Vault key to sign/verify, encrypt/decrypt, and wrap/unwrap data. */ -import { createHash } from "crypto"; +import { createHash } from "node:crypto"; import { CryptographyClient, KeyClient } from "@azure/keyvault-keys"; import { DefaultAzureCredential } from "@azure/identity"; @@ -32,7 +32,7 @@ export async function main(): Promise { const cryptoClient = new CryptographyClient( myWorkKey.id!, // You can use either the key or the key Id i.e. its url to create a CryptographyClient. - credential + credential, ); // Sign and Verify @@ -56,14 +56,17 @@ export async function main(): Promise { }); console.log("encrypt result: ", encrypt); - const decrypt = await cryptoClient.decrypt({ algorithm: "RSA1_5", ciphertext: encrypt.result }); + const decrypt = await cryptoClient.decrypt({ + algorithm: "RSA-OAEP-256", + ciphertext: encrypt.result, + }); console.log("decrypt: ", decrypt.result.toString()); // Wrap and unwrap - const wrapped = await cryptoClient.wrapKey("RSA-OAEP", Buffer.from("My Message")); + const wrapped = await cryptoClient.wrapKey("RSA-OAEP-256", Buffer.from("My Message")); console.log("wrap result: ", wrapped); - const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP", wrapped.result); + const unwrapped = await cryptoClient.unwrapKey("RSA-OAEP-256", wrapped.result); console.log("unwrap result: ", unwrapped); } diff --git a/sdk/keyvault/keyvault-keys/src/cryptographyClientModels.ts b/sdk/keyvault/keyvault-keys/src/cryptographyClientModels.ts index 4d1195c79dd0..6963ec21a6ae 100644 --- a/sdk/keyvault/keyvault-keys/src/cryptographyClientModels.ts +++ b/sdk/keyvault/keyvault-keys/src/cryptographyClientModels.ts @@ -7,82 +7,20 @@ import type { JsonWebKey } from "./generated/models/index.js"; import { JsonWebKeyEncryptionAlgorithm as EncryptionAlgorithm, JsonWebKeyCurveName as KeyCurveName, + KnownJsonWebKeyCurveName as KnownKeyCurveNames, + KnownJsonWebKeySignatureAlgorithm as KnownSignatureAlgorithms, + KnownJsonWebKeyEncryptionAlgorithm as KnownEncryptionAlgorithms, JsonWebKeySignatureAlgorithm as SignatureAlgorithm, } from "./generated/models/index.js"; -export { KeyCurveName, EncryptionAlgorithm, SignatureAlgorithm }; - -/** Known values of {@link KeyCurveName} that the service accepts. */ -export enum KnownKeyCurveNames { - /** The NIST P-256 elliptic curve, AKA SECG curve SECP256R1. */ - P256 = "P-256", - /** The NIST P-384 elliptic curve, AKA SECG curve SECP384R1. */ - P384 = "P-384", - /** The NIST P-521 elliptic curve, AKA SECG curve SECP521R1. */ - P521 = "P-521", - /** The SECG SECP256K1 elliptic curve. */ - P256K = "P-256K", -} - -/** Known values of {@link SignatureAlgorithm} that the service accepts. */ -export enum KnownSignatureAlgorithms { - /** RSASSA-PSS using SHA-256 and MGF1 with SHA-256, as described in https://tools.ietf.org/html/rfc7518 */ - PS256 = "PS256", - /** RSASSA-PSS using SHA-384 and MGF1 with SHA-384, as described in https://tools.ietf.org/html/rfc7518 */ - PS384 = "PS384", - /** RSASSA-PSS using SHA-512 and MGF1 with SHA-512, as described in https://tools.ietf.org/html/rfc7518 */ - PS512 = "PS512", - /** RSASSA-PKCS1-v1_5 using SHA-256, as described in https://tools.ietf.org/html/rfc7518 */ - RS256 = "RS256", - /** RSASSA-PKCS1-v1_5 using SHA-384, as described in https://tools.ietf.org/html/rfc7518 */ - RS384 = "RS384", - /** RSASSA-PKCS1-v1_5 using SHA-512, as described in https://tools.ietf.org/html/rfc7518 */ - RS512 = "RS512", - /** Reserved */ - Rsnull = "RSNULL", - /** ECDSA using P-256 and SHA-256, as described in https://tools.ietf.org/html/rfc7518. */ - ES256 = "ES256", - /** ECDSA using P-384 and SHA-384, as described in https://tools.ietf.org/html/rfc7518 */ - ES384 = "ES384", - /** ECDSA using P-521 and SHA-512, as described in https://tools.ietf.org/html/rfc7518 */ - ES512 = "ES512", - /** ECDSA using P-256K and SHA-256, as described in https://tools.ietf.org/html/rfc7518 */ - ES256K = "ES256K", -} - -/** Known values of {@link EncryptionAlgorithm} that the service accepts. */ -export enum KnownEncryptionAlgorithms { - /** Encryption Algorithm - RSA-OAEP */ - RSAOaep = "RSA-OAEP", - /** Encryption Algorithm - RSA-OAEP-256 */ - RSAOaep256 = "RSA-OAEP-256", - /** Encryption Algorithm - RSA1_5 */ - RSA15 = "RSA1_5", - /** Encryption Algorithm - A128GCM */ - A128GCM = "A128GCM", - /** Encryption Algorithm - A192GCM */ - A192GCM = "A192GCM", - /** Encryption Algorithm - A256GCM */ - A256GCM = "A256GCM", - /** Encryption Algorithm - A128KW */ - A128KW = "A128KW", - /** Encryption Algorithm - A192KW */ - A192KW = "A192KW", - /** Encryption Algorithm - A256KW */ - A256KW = "A256KW", - /** Encryption Algorithm - A128CBC */ - A128CBC = "A128CBC", - /** Encryption Algorithm - A192CBC */ - A192CBC = "A192CBC", - /** Encryption Algorithm - A256CBC */ - A256CBC = "A256CBC", - /** Encryption Algorithm - A128CBCPAD */ - A128Cbcpad = "A128CBCPAD", - /** Encryption Algorithm - A192CBCPAD */ - A192Cbcpad = "A192CBCPAD", - /** Encryption Algorithm - A256CBCPAD */ - A256Cbcpad = "A256CBCPAD", -} +export { + KeyCurveName, + EncryptionAlgorithm, + KnownEncryptionAlgorithms, + SignatureAlgorithm, + KnownKeyCurveNames, + KnownSignatureAlgorithms, +}; /** * Supported algorithms for key wrapping/unwrapping diff --git a/sdk/keyvault/keyvault-keys/src/generated/index.ts b/sdk/keyvault/keyvault-keys/src/generated/index.ts index 0118cdcf4e02..ceb88d61e40a 100644 --- a/sdk/keyvault/keyvault-keys/src/generated/index.ts +++ b/sdk/keyvault/keyvault-keys/src/generated/index.ts @@ -24,6 +24,7 @@ export { JsonWebKey, KeyVaultError, ErrorModel, + ErrorModel_1, KeyImportParameters, DeletedKeyBundle, KeyUpdateParameters, diff --git a/sdk/keyvault/keyvault-keys/src/generated/models/index.ts b/sdk/keyvault/keyvault-keys/src/generated/models/index.ts index e0e218b98a20..a18539452c7a 100644 --- a/sdk/keyvault/keyvault-keys/src/generated/models/index.ts +++ b/sdk/keyvault/keyvault-keys/src/generated/models/index.ts @@ -17,6 +17,7 @@ export { JsonWebKey, KeyVaultError, ErrorModel, + ErrorModel_1, KeyImportParameters, DeletedKeyBundle, KeyUpdateParameters, diff --git a/sdk/keyvault/keyvault-keys/src/generated/models/models.ts b/sdk/keyvault/keyvault-keys/src/generated/models/models.ts index c5b8bce6f187..9211391f3542 100644 --- a/sdk/keyvault/keyvault-keys/src/generated/models/models.ts +++ b/sdk/keyvault/keyvault-keys/src/generated/models/models.ts @@ -205,7 +205,7 @@ export enum KnownJsonWebKeyCurveName { /** The NIST P-521 elliptic curve, AKA SECG curve SECP521R1. */ P521 = "P-521", /** The SECG SECP256K1 elliptic curve. */ - P256_K = "P-256K", + P256K = "P-256K", } /** @@ -424,30 +424,48 @@ export interface KeyVaultError { export function keyVaultErrorDeserializer(item: any): KeyVaultError { return { - error: !item["error"] ? item["error"] : errorDeserializer(item["error"]), + error: !item["error"] + ? item["error"] + : _keyVaultErrorErrorDeserializer(item["error"]), }; } -/** The key vault server error. */ -export interface ErrorModel { +/** Alias for ErrorModel */ +export type ErrorModel = { + code?: string; + message?: string; + innerError?: ErrorModel_1; +} | null; + +/** model interface _KeyVaultErrorError */ +export interface _KeyVaultErrorError { /** The error code. */ readonly code?: string; /** The error message. */ readonly message?: string; /** The key vault server error. */ - readonly innerError?: ErrorModel; + readonly innerError?: ErrorModel_1; } -export function errorDeserializer(item: any): ErrorModel { +export function _keyVaultErrorErrorDeserializer( + item: any, +): _KeyVaultErrorError { return { code: item["code"], message: item["message"], innerError: !item["innererror"] ? item["innererror"] - : errorDeserializer(item["innererror"]), + : _keyVaultErrorErrorDeserializer(item["innererror"]), }; } +/** Alias for ErrorModel */ +export type ErrorModel_1 = { + code?: string; + message?: string; + innerError?: ErrorModel_1; +} | null; + /** The key import parameters. */ export interface KeyImportParameters { /** Whether to import as a hardware key (HSM) or software key. */ @@ -652,40 +670,36 @@ export function keyOperationsParametersSerializer( /** An algorithm used for encryption and decryption. */ export enum KnownJsonWebKeyEncryptionAlgorithm { - /** RSAES using Optimal Asymmetric Encryption Padding (OAEP), as described in https://tools.ietf.org/html/rfc3447, with the default parameters specified by RFC 3447 in Section A.2.1. Those default parameters are using a hash function of SHA-1 and a mask generation function of MGF1 with SHA-1. */ - RSA_OAEP = "RSA-OAEP", + /** [Not recommended] RSAES using Optimal Asymmetric Encryption Padding (OAEP), as described in https://tools.ietf.org/html/rfc3447, with the default parameters specified by RFC 3447 in Section A.2.1. Those default parameters are using a hash function of SHA-1 and a mask generation function of MGF1 with SHA-1. Microsoft recommends using RSA_OAEP_256 or stronger algorithms for enhanced security. Microsoft does *not* recommend RSA_OAEP, which is included solely for backwards compatibility. RSA_OAEP utilizes SHA1, which has known collision problems. */ + RSAOaep = "RSA-OAEP", /** RSAES using Optimal Asymmetric Encryption Padding with a hash function of SHA-256 and a mask generation function of MGF1 with SHA-256. */ - RSA_OAEP256 = "RSA-OAEP-256", - /** RSAES-PKCS1-V1_5 key encryption, as described in https://tools.ietf.org/html/rfc3447. */ - RSA1_5 = "RSA1_5", + RSAOaep256 = "RSA-OAEP-256", + /** [Not recommended] RSAES-PKCS1-V1_5 key encryption, as described in https://tools.ietf.org/html/rfc3447. Microsoft recommends using RSA_OAEP_256 or stronger algorithms for enhanced security. Microsoft does *not* recommend RSA_1_5, which is included solely for backwards compatibility. Cryptographic standards no longer consider RSA with the PKCS#1 v1.5 padding scheme secure for encryption. */ + RSA15 = "RSA1_5", /** 128-bit AES-GCM. */ - A128_GCM = "A128GCM", + A128GCM = "A128GCM", /** 192-bit AES-GCM. */ - A192_GCM = "A192GCM", + A192GCM = "A192GCM", /** 256-bit AES-GCM. */ - A256_GCM = "A256GCM", + A256GCM = "A256GCM", /** 128-bit AES key wrap. */ - A128_KW = "A128KW", + A128KW = "A128KW", /** 192-bit AES key wrap. */ - A192_KW = "A192KW", + A192KW = "A192KW", /** 256-bit AES key wrap. */ - A256_KW = "A256KW", + A256KW = "A256KW", /** 128-bit AES-CBC. */ - A128_CBC = "A128CBC", + A128CBC = "A128CBC", /** 192-bit AES-CBC. */ - A192_CBC = "A192CBC", + A192CBC = "A192CBC", /** 256-bit AES-CBC. */ - A256_CBC = "A256CBC", + A256CBC = "A256CBC", /** 128-bit AES-CBC with PKCS padding. */ - A128_CBCPAD = "A128CBCPAD", + A128Cbcpad = "A128CBCPAD", /** 192-bit AES-CBC with PKCS padding. */ - A192_CBCPAD = "A192CBCPAD", + A192Cbcpad = "A192CBCPAD", /** 256-bit AES-CBC with PKCS padding. */ - A256_CBCPAD = "A256CBCPAD", - /** CKM AES key wrap. */ - CKM_AES_KEY_WRAP = "CKM_AES_KEY_WRAP", - /** CKM AES key wrap with padding. */ - CKM_AES_KEY_WRAP_PAD = "CKM_AES_KEY_WRAP_PAD", + A256Cbcpad = "A256CBCPAD", } /** @@ -693,9 +707,9 @@ export enum KnownJsonWebKeyEncryptionAlgorithm { * {@link KnownJsonWebKeyEncryptionAlgorithm} can be used interchangeably with JsonWebKeyEncryptionAlgorithm, * this enum contains the known values that the service supports. * ### Known values supported by the service - * **RSA-OAEP**: RSAES using Optimal Asymmetric Encryption Padding (OAEP), as described in https:\//tools.ietf.org\/html\/rfc3447, with the default parameters specified by RFC 3447 in Section A.2.1. Those default parameters are using a hash function of SHA-1 and a mask generation function of MGF1 with SHA-1. \ + * **RSA-OAEP**: [Not recommended] RSAES using Optimal Asymmetric Encryption Padding (OAEP), as described in https:\//tools.ietf.org\/html\/rfc3447, with the default parameters specified by RFC 3447 in Section A.2.1. Those default parameters are using a hash function of SHA-1 and a mask generation function of MGF1 with SHA-1. Microsoft recommends using RSA_OAEP_256 or stronger algorithms for enhanced security. Microsoft does *not* recommend RSA_OAEP, which is included solely for backwards compatibility. RSA_OAEP utilizes SHA1, which has known collision problems. \ * **RSA-OAEP-256**: RSAES using Optimal Asymmetric Encryption Padding with a hash function of SHA-256 and a mask generation function of MGF1 with SHA-256. \ - * **RSA1_5**: RSAES-PKCS1-V1_5 key encryption, as described in https:\//tools.ietf.org\/html\/rfc3447. \ + * **RSA1_5**: [Not recommended] RSAES-PKCS1-V1_5 key encryption, as described in https:\//tools.ietf.org\/html\/rfc3447. Microsoft recommends using RSA_OAEP_256 or stronger algorithms for enhanced security. Microsoft does *not* recommend RSA_1_5, which is included solely for backwards compatibility. Cryptographic standards no longer consider RSA with the PKCS#1 v1.5 padding scheme secure for encryption. \ * **A128GCM**: 128-bit AES-GCM. \ * **A192GCM**: 192-bit AES-GCM. \ * **A256GCM**: 256-bit AES-GCM. \ @@ -708,8 +722,6 @@ export enum KnownJsonWebKeyEncryptionAlgorithm { * **A128CBCPAD**: 128-bit AES-CBC with PKCS padding. \ * **A192CBCPAD**: 192-bit AES-CBC with PKCS padding. \ * **A256CBCPAD**: 256-bit AES-CBC with PKCS padding. \ - * **CKM_AES_KEY_WRAP**: CKM AES key wrap. \ - * **CKM_AES_KEY_WRAP_PAD**: CKM AES key wrap with padding. */ export type JsonWebKeyEncryptionAlgorithm = string; @@ -783,7 +795,7 @@ export enum KnownJsonWebKeySignatureAlgorithm { /** RSASSA-PKCS1-v1_5 using SHA-512, as described in https://tools.ietf.org/html/rfc7518 */ RS512 = "RS512", /** Reserved */ - RSNULL = "RSNULL", + Rsnull = "RSNULL", /** ECDSA using P-256 and SHA-256, as described in https://tools.ietf.org/html/rfc7518. */ ES256 = "ES256", /** ECDSA using P-384 and SHA-384, as described in https://tools.ietf.org/html/rfc7518 */ @@ -791,7 +803,7 @@ export enum KnownJsonWebKeySignatureAlgorithm { /** ECDSA using P-521 and SHA-512, as described in https://tools.ietf.org/html/rfc7518 */ ES512 = "ES512", /** ECDSA using P-256K and SHA-256, as described in https://tools.ietf.org/html/rfc7518 */ - ES256_K = "ES256K", + ES256K = "ES256K", } /**