]> git.proxmox.com Git - mirror_edk2.git/blobdiff - CryptoPkg/Library/TlsLib/TlsConfig.c
CryptoPkg: Extend Tls function library
[mirror_edk2.git] / CryptoPkg / Library / TlsLib / TlsConfig.c
index 0673c9d5322e87ce85649bf953cc98da660fd012..dbe1f0652996e4ad8e7505fae8594b8224eb7af6 100644 (file)
@@ -62,6 +62,38 @@ STATIC CONST TLS_CIPHER_MAPPING  TlsCipherMappingTable[] = {
   MAP (0x0068, "DH-DSS-AES256-SHA256"),             /// TLS_DH_DSS_WITH_AES_256_CBC_SHA256\r
   MAP (0x0069, "DH-RSA-AES256-SHA256"),             /// TLS_DH_RSA_WITH_AES_256_CBC_SHA256\r
   MAP (0x006B, "DHE-RSA-AES256-SHA256"),            /// TLS_DHE_RSA_WITH_AES_256_CBC_SHA256\r
+  MAP (0x009F, "DHE-RSA-AES256-GCM-SHA384"),        /// TLS_DHE_RSA_WITH_AES_256_GCM_SHA384\r
+  MAP (0xC02B, "ECDHE-ECDSA-AES128-GCM-SHA256"),    /// TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256\r
+  MAP (0xC02C, "ECDHE-ECDSA-AES256-GCM-SHA384"),    /// TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384\r
+  MAP (0xC030, "ECDHE-RSA-AES256-GCM-SHA384"),      /// TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\r
+};\r
+\r
+typedef struct {\r
+  //\r
+  // TLS Algorithm\r
+  //\r
+  UINT8          Algo;\r
+  //\r
+  // TLS Algorithm name\r
+  //\r
+  CONST CHAR8    *Name;\r
+} TLS_ALGO_TO_NAME;\r
+\r
+STATIC CONST TLS_ALGO_TO_NAME  TlsHashAlgoToName[] = {\r
+  { TlsHashAlgoNone,   NULL     },\r
+  { TlsHashAlgoMd5,    "MD5"    },\r
+  { TlsHashAlgoSha1,   "SHA1"   },\r
+  { TlsHashAlgoSha224, "SHA224" },\r
+  { TlsHashAlgoSha256, "SHA256" },\r
+  { TlsHashAlgoSha384, "SHA384" },\r
+  { TlsHashAlgoSha512, "SHA512" },\r
+};\r
+\r
+STATIC CONST TLS_ALGO_TO_NAME  TlsSignatureAlgoToName[] = {\r
+  { TlsSignatureAlgoAnonymous, NULL    },\r
+  { TlsSignatureAlgoRsa,       "RSA"   },\r
+  { TlsSignatureAlgoDsa,       "DSA"   },\r
+  { TlsSignatureAlgoEcdsa,     "ECDSA" },\r
 };\r
 \r
 /**\r
@@ -831,11 +863,107 @@ ON_EXIT:
 /**\r
   Adds the local private key to the specified TLS object.\r
 \r
-  This function adds the local private key (PEM-encoded RSA or PKCS#8 private\r
+  This function adds the local private key (DER-encoded or PEM-encoded or PKCS#8 private\r
   key) into the specified TLS object for TLS negotiation.\r
 \r
   @param[in]  Tls         Pointer to the TLS object.\r
-  @param[in]  Data        Pointer to the data buffer of a PEM-encoded RSA\r
+  @param[in]  Data        Pointer to the data buffer of a DER-encoded or PEM-encoded\r
+                          or PKCS#8 private key.\r
+  @param[in]  DataSize    The size of data buffer in bytes.\r
+  @param[in]  Password    Pointer to NULL-terminated private key password, set it to NULL\r
+                          if private key not encrypted.\r
+\r
+  @retval  EFI_SUCCESS     The operation succeeded.\r
+  @retval  EFI_UNSUPPORTED This function is not supported.\r
+  @retval  EFI_ABORTED     Invalid private key data.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsSetHostPrivateKeyEx (\r
+  IN     VOID   *Tls,\r
+  IN     VOID   *Data,\r
+  IN     UINTN  DataSize,\r
+  IN     VOID   *Password  OPTIONAL\r
+  )\r
+{\r
+  TLS_CONNECTION  *TlsConn;\r
+  BIO             *Bio;\r
+  EVP_PKEY        *Pkey;\r
+  BOOLEAN         Verify;\r
+\r
+  TlsConn = (TLS_CONNECTION *)Tls;\r
+\r
+  if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize == 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  // Try to parse the private key in DER format or un-encrypted PKC#8\r
+  if (SSL_use_PrivateKey_ASN1 (\r
+        EVP_PKEY_RSA,\r
+        TlsConn->Ssl,\r
+        Data,\r
+        (long)DataSize\r
+        ) == 1)\r
+  {\r
+    goto verify;\r
+  }\r
+\r
+  if (SSL_use_PrivateKey_ASN1 (\r
+        EVP_PKEY_DSA,\r
+        TlsConn->Ssl,\r
+        Data,\r
+        (long)DataSize\r
+        ) == 1)\r
+  {\r
+    goto verify;\r
+  }\r
+\r
+  if (SSL_use_PrivateKey_ASN1 (\r
+        EVP_PKEY_EC,\r
+        TlsConn->Ssl,\r
+        Data,\r
+        (long)DataSize\r
+        ) == 1)\r
+  {\r
+    goto verify;\r
+  }\r
+\r
+  // Try to parse the private key in PEM format or encrypted PKC#8\r
+  Bio = BIO_new_mem_buf (Data, (int)DataSize);\r
+  if (Bio != NULL) {\r
+    Verify = FALSE;\r
+    Pkey   = PEM_read_bio_PrivateKey (Bio, NULL, NULL, Password);\r
+    if ((Pkey != NULL) && (SSL_use_PrivateKey (TlsConn->Ssl, Pkey) == 1)) {\r
+      Verify = TRUE;\r
+    }\r
+\r
+    EVP_PKEY_free (Pkey);\r
+    BIO_free (Bio);\r
+\r
+    if (Verify) {\r
+      goto verify;\r
+    }\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+\r
+verify:\r
+  if (SSL_check_private_key (TlsConn->Ssl) == 1) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  return EFI_ABORTED;\r
+}\r
+\r
+/**\r
+  Adds the local private key to the specified TLS object.\r
+\r
+  This function adds the local private key (DER-encoded or PEM-encoded or PKCS#8 private\r
+  key) into the specified TLS object for TLS negotiation.\r
+\r
+  @param[in]  Tls         Pointer to the TLS object.\r
+  @param[in]  Data        Pointer to the data buffer of a DER-encoded or PEM-encoded\r
                           or PKCS#8 private key.\r
   @param[in]  DataSize    The size of data buffer in bytes.\r
 \r
@@ -852,7 +980,7 @@ TlsSetHostPrivateKey (
   IN     UINTN  DataSize\r
   )\r
 {\r
-  return EFI_UNSUPPORTED;\r
+  return TlsSetHostPrivateKeyEx (Tls, Data, DataSize, NULL);\r
 }\r
 \r
 /**\r
@@ -879,6 +1007,188 @@ TlsSetCertRevocationList (
   return EFI_UNSUPPORTED;\r
 }\r
 \r
+/**\r
+  Set the signature algorithm list to used by the TLS object.\r
+\r
+  This function sets the signature algorithms for use by a specified TLS object.\r
+\r
+  @param[in]  Tls                Pointer to a TLS object.\r
+  @param[in]  Data               Array of UINT8 of signature algorithms. The array consists of\r
+                                 pairs of the hash algorithm and the signature algorithm as defined\r
+                                 in RFC 5246\r
+  @param[in]  DataSize           The length the SignatureAlgoList. Must be divisible by 2.\r
+\r
+  @retval  EFI_SUCCESS           The signature algorithm list was set successfully.\r
+  @retval  EFI_INVALID_PARAMETER The parameters are invalid.\r
+  @retval  EFI_UNSUPPORTED       No supported TLS signature algorithm was found in SignatureAlgoList\r
+  @retval  EFI_OUT_OF_RESOURCES  Memory allocation failed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsSetSignatureAlgoList (\r
+  IN     VOID   *Tls,\r
+  IN     UINT8  *Data,\r
+  IN     UINTN  DataSize\r
+  )\r
+{\r
+  TLS_CONNECTION  *TlsConn;\r
+  UINTN           Index;\r
+  UINTN           SignAlgoStrSize;\r
+  CHAR8           *SignAlgoStr;\r
+  CHAR8           *Pos;\r
+  UINT8           *SignatureAlgoList;\r
+  EFI_STATUS      Status;\r
+\r
+  TlsConn = (TLS_CONNECTION *)Tls;\r
+\r
+  if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize < 3) ||\r
+      ((DataSize % 2) == 0) || (Data[0] != DataSize - 1))\r
+  {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SignatureAlgoList = Data + 1;\r
+  SignAlgoStrSize   = 0;\r
+  for (Index = 0; Index < Data[0]; Index += 2) {\r
+    CONST CHAR8  *Tmp;\r
+\r
+    if (SignatureAlgoList[Index] >= ARRAY_SIZE (TlsHashAlgoToName)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Tmp = TlsHashAlgoToName[SignatureAlgoList[Index]].Name;\r
+    if (!Tmp) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    // Add 1 for the '+'\r
+    SignAlgoStrSize += AsciiStrLen (Tmp) + 1;\r
+\r
+    if (SignatureAlgoList[Index + 1] >= ARRAY_SIZE (TlsSignatureAlgoToName)) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    Tmp = TlsSignatureAlgoToName[SignatureAlgoList[Index + 1]].Name;\r
+    if (!Tmp) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    // Add 1 for the ':' or for the NULL terminator\r
+    SignAlgoStrSize += AsciiStrLen (Tmp) + 1;\r
+  }\r
+\r
+  if (!SignAlgoStrSize) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  SignAlgoStr = AllocatePool (SignAlgoStrSize);\r
+  if (SignAlgoStr == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Pos = SignAlgoStr;\r
+  for (Index = 0; Index < Data[0]; Index += 2) {\r
+    CONST CHAR8  *Tmp;\r
+\r
+    Tmp = TlsHashAlgoToName[SignatureAlgoList[Index]].Name;\r
+    CopyMem (Pos, Tmp, AsciiStrLen (Tmp));\r
+    Pos   += AsciiStrLen (Tmp);\r
+    *Pos++ = '+';\r
+\r
+    Tmp = TlsSignatureAlgoToName[SignatureAlgoList[Index + 1]].Name;\r
+    CopyMem (Pos, Tmp, AsciiStrLen (Tmp));\r
+    Pos   += AsciiStrLen (Tmp);\r
+    *Pos++ = ':';\r
+  }\r
+\r
+  *(Pos - 1) = '\0';\r
+\r
+  if (SSL_set1_sigalgs_list (TlsConn->Ssl, SignAlgoStr) < 1) {\r
+    Status = EFI_INVALID_PARAMETER;\r
+  } else {\r
+    Status = EFI_SUCCESS;\r
+  }\r
+\r
+  FreePool (SignAlgoStr);\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Set the EC curve to be used for TLS flows\r
+\r
+  This function sets the EC curve to be used for TLS flows.\r
+\r
+  @param[in]  Tls                Pointer to a TLS object.\r
+  @param[in]  Data               An EC named curve as defined in section 5.1.1 of RFC 4492.\r
+  @param[in]  DataSize           Size of Data, it should be sizeof (UINT32)\r
+\r
+  @retval  EFI_SUCCESS           The EC curve was set successfully.\r
+  @retval  EFI_INVALID_PARAMETER The parameters are invalid.\r
+  @retval  EFI_UNSUPPORTED       The requested TLS EC curve is not supported\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsSetEcCurve (\r
+  IN     VOID   *Tls,\r
+  IN     UINT8  *Data,\r
+  IN     UINTN  DataSize\r
+  )\r
+{\r
+ #if !FixedPcdGetBool (PcdOpensslEcEnabled)\r
+  return EFI_UNSUPPORTED;\r
+ #else\r
+  TLS_CONNECTION  *TlsConn;\r
+  EC_KEY          *EcKey;\r
+  INT32           Nid;\r
+  INT32           Ret;\r
+\r
+  TlsConn = (TLS_CONNECTION *)Tls;\r
+\r
+  if ((TlsConn == NULL) || (TlsConn->Ssl == NULL) || (Data == NULL) || (DataSize != sizeof (UINT32))) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  switch (*((UINT32 *)Data)) {\r
+    case TlsEcNamedCurveSecp256r1:\r
+      return EFI_UNSUPPORTED;\r
+    case TlsEcNamedCurveSecp384r1:\r
+      Nid = NID_secp384r1;\r
+      break;\r
+    case TlsEcNamedCurveSecp521r1:\r
+      Nid = NID_secp521r1;\r
+      break;\r
+    case TlsEcNamedCurveX25519:\r
+      Nid = NID_X25519;\r
+      break;\r
+    case TlsEcNamedCurveX448:\r
+      Nid = NID_X448;\r
+      break;\r
+    default:\r
+      return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (SSL_set1_curves (TlsConn->Ssl, &Nid, 1) != 1) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  EcKey = EC_KEY_new_by_curve_name (Nid);\r
+  if (EcKey == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Ret = SSL_set_tmp_ecdh (TlsConn->Ssl, EcKey);\r
+  EC_KEY_free (EcKey);\r
+\r
+  if (Ret != 1) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+ #endif\r
+}\r
+\r
 /**\r
   Gets the protocol version used by the specified TLS connection.\r
 \r
@@ -1306,3 +1616,53 @@ TlsGetCertRevocationList (
 {\r
   return EFI_UNSUPPORTED;\r
 }\r
+\r
+/**\r
+  Derive keying material from a TLS connection.\r
+\r
+  This function exports keying material using the mechanism described in RFC\r
+  5705.\r
+\r
+  @param[in]      Tls          Pointer to the TLS object\r
+  @param[in]      Label        Description of the key for the PRF function\r
+  @param[in]      Context      Optional context\r
+  @param[in]      ContextLen   The length of the context value in bytes\r
+  @param[out]     KeyBuffer    Buffer to hold the output of the TLS-PRF\r
+  @param[in]      KeyBufferLen The length of the KeyBuffer\r
+\r
+  @retval  EFI_SUCCESS             The operation succeeded.\r
+  @retval  EFI_INVALID_PARAMETER   The TLS object is invalid.\r
+  @retval  EFI_PROTOCOL_ERROR      Some other error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TlsGetExportKey (\r
+  IN     VOID        *Tls,\r
+  IN     CONST VOID  *Label,\r
+  IN     CONST VOID  *Context,\r
+  IN     UINTN       ContextLen,\r
+  OUT    VOID        *KeyBuffer,\r
+  IN     UINTN       KeyBufferLen\r
+  )\r
+{\r
+  TLS_CONNECTION  *TlsConn;\r
+\r
+  TlsConn = (TLS_CONNECTION *)Tls;\r
+\r
+  if ((TlsConn == NULL) || (TlsConn->Ssl == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  return SSL_export_keying_material (\r
+           TlsConn->Ssl,\r
+           KeyBuffer,\r
+           KeyBufferLen,\r
+           Label,\r
+           AsciiStrLen (Label),\r
+           Context,\r
+           ContextLen,\r
+           Context != NULL\r
+           ) == 1 ?\r
+         EFI_SUCCESS : EFI_PROTOCOL_ERROR;\r
+}\r