Main Content

CWE Rule 573

Improper Following of Specification by Caller

Since R2024a

Description

Rule Description

The product does not follow or incorrectly follows the specifications as required by the implementation language, environment, framework, protocol, or platform.

Polyspace Implementation

The rule checker checks for these issues:

  • Context initialized incorrectly for cryptographic operation

  • Context initialized incorrectly for digest operation

  • Incompatible padding for RSA algorithm operation

  • Incorrect key for cryptographic algorithm

  • Missing blinding for RSA algorithm

  • Missing cipher algorithm

  • Missing cipher key

  • Missing data for encryption, decryption or signing operation

  • Missing final step after hashing update operation

  • Missing hash algorithm

  • Missing parameters for key generation

  • Missing peer key

  • Missing private key

  • Missing private key for X.509 certificate

  • Missing public key

  • Modification of internal buffer returned from non-reentrant standard function

  • TLS/SSL connection method not set

  • TLS/SSL connection method set incorrectly

Examples

expand all

Issue

This issue occurs when you initialize an EVP_PKEY_CTX object for a specific public key cryptography operation but use the object for a different operation.

For instance, you initialize the context for encryption.

ret = EVP_PKEY_encrypt_init(ctx);
However, you use the context for decryption without reinitializing the context.
ret = EVP_PKEY_decrypt(ctx, out, &out_len, in, in_len);

The checker detects if the context object used in these functions has been initialized by using the corresponding initialization functions: EVP_PKEY_paramgen, EVP_PKEY_keygen, EVP_PKEY_encrypt, EVP_PKEY_verify, EVP_PKEY_verify_recover,EVP_PKEY_decrypt, EVP_PKEY_sign, EVP_PKEY_derive,and EVP_PKEY_derive_set_peer.

Risk

Mixing up different operations on the same context can lead to obscure code. It is difficult to determine at a glance whether the current object is used for encryption, decryption, signature, or another operation. The mixup can also lead to a failure in the operation or unexpected ciphertext.

Fix

After you set up a context for a certain family of operations, use the context for only that family of operations.For instance, use these pairs of functions for initialization and usage of the EVP_PKEY_CTX context object.

  • For encryption with EVP_PKEY_encrypt, initialize the context with EVP_PKEY_encrypt_init.

  • For signature verification with EVP_PKEY_verify, initialize the context with EVP_PKEY_verify_init.

  • For key generation with EVP_PKEY_keygen, initialize the context with EVP_PKEY_keygen_init.

If you want to reuse an existing context object for a different family of operations, reinitialize the context.

Example — Encryption Using Context Initialized for Decryption
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf10;
size_t out_len10;
int func(unsigned char *src, size_t len, EVP_PKEY_CTX *ctx){
  if (ctx == NULL) fatal_error(); 

  ret = EVP_PKEY_decrypt_init(ctx); 
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf10, &out_len10, src, len); //Noncompliant
}

In this example, the context is initialized for decryption but used for encryption.

Correction — Use One Family of Operations

One possible correction is to initialize the object for encryption.

#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf10;
size_t out_len10;
int func(unsigned char *src, size_t len, EVP_PKEY_CTX *ctx){
  if (ctx == NULL) fatal_error(); 

  ret = EVP_PKEY_encrypt_init(ctx); 
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf10, &out_len10, src, len);
}
Issue

This issue occurs when you initialize an EVP_MD_CTX context object for a specific digest operation but use the context for a different operation.

For instance, you initialize the context for creating a message digest only.

ret = EVP_DigestInit(ctx, EVP_sha256())
However, you perform a final step for signing:
ret = EVP_SignFinal(&ctx, out, &out_len, pkey);
The error is shown only if the final step is not consistent with the initialization of the context. If the intermediate update steps are inconsistent, it does not trigger an error because the intermediate steps do not depend on the nature of the operation. For instance, EVP_DigestUpdate works identically to EVP_SignUpdate.

Risk

Mixing up different operations on the same context can lead to obscure code. It is difficult to determine at a glance whether the current object is used for message digest creation, signing, or verification. The mixup can also lead to a failure in the operation or unexpected message digest.

Fix

After you set up a context for a certain family of operations, use the context for only that family of operations. For instance, use these pairs of functions for initialization and final steps.

  • EVP_DigestInit : EVP_DigestFinal

  • EVP_DigestInit_ex : EVP_DigestFinal_ex

  • EVP_DigestSignInit : EVP_DigestSignFinal

If you want to reuse an existing context object for a different family of operations, reinitialize the context.

Example — Inconsistent Initial and Final Digest Operation
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf16;
unsigned int out_len16;

void func(unsigned char *src, size_t len){
  EVP_MD_CTX* ctx = EVP_MD_CTX_create();

  ret = EVP_SignInit_ex(ctx, EVP_sha256(), NULL);
  if (ret != 1) fatal_error();

  ret = EVP_SignUpdate(ctx, src, len);
  if (ret != 1) fatal_error();

  ret = EVP_DigestSignFinal(ctx, out_buf16, (size_t*) out_len16); //Noncompliant

  if (ret != 1) fatal_error();
}

In this example, the context object is initialized for signing only with EVP_SignInit but the final step attempts to create a signed digest with EVP_DigestSignFinal.

Correction — Use One Family of Operations

One possible correction is to use the context object for signing only. Change the final step to EVP_SignFinal in keeping with the initialization step.

#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf16;
unsigned int out_len16;

void corrected_cryptomdbadfunction(unsigned char *src, size_t len, EVP_PKEY* pkey){
  EVP_MD_CTX* ctx = EVP_MD_CTX_create();

  ret = EVP_SignInit_ex(ctx, EVP_sha256(), NULL); 
  if (ret != 1) fatal_error();

  ret = EVP_SignUpdate(ctx, src, len);
  if (ret != 1) fatal_error();

  ret = EVP_SignFinal(ctx, out_buf16, &out_len16, pkey); 
  if (ret != 1) fatal_error();
}
Issue

This issue occurs when you perform an RSA algorithm operation on a context object that is not compatible with the padding previously associated with the object.

For instance, you associate the OAEP padding scheme with a context object but later use the context for signature verification, an operation that the padding scheme does not support.

ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
...
ret = EVP_PKEY_verify(ctx, out, out_len, in, in_len);

Risk

Padding schemes remove determinism from the RSA algorithm and protect RSA operations from certain kinds of attack.

When you use an incorrect padding scheme, the RSA operation can fail or result in unexpected ciphertext.

Fix

Before performing an RSA operation, associate the context object with a padding scheme that is compatible with the operation.

  • Encryption: Use the OAEP padding scheme.

    For instance, use the EVP_PKEY_CTX_set_rsa_padding function with the argument RSA_PKCS1_OAEP_PADDING or the RSA_padding_add_PKCS1_OAEP function.

    ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
    
    You can also use the PKCS#1v1.5 or SSLv23 schemes. Be aware that these schemes are considered insecure.

    You can then use functions such as EVP_PKEY_encrypt / EVP_PKEY_decrypt or RSA_public_encrypt / RSA_private_decrypt on the context.

  • Signature: Use the RSA-PSS padding scheme.

    For instance, use the EVP_PKEY_CTX_set_rsa_padding function with the argument RSA_PKCS1_PSS_PADDING.

    ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING);
    You can also use the ANSI X9.31, PKCS#1v1.5, or SSLv23 schemes. Be aware that these schemes are considered insecure.

    You can then use functions such as the EVP_PKEY_sign-EVP_PKEY_verify pair or the RSA_private_encrypt-RSA_public_decrypt pair on the context.

If you perform two kinds of operation with the same context, after the first operation, reset the padding scheme in the context before the second operation.

Example — OAEP Padding for Signature Operation
#include <stddef.h>
#include <openssl/rsa.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;

int func(unsigned char *src, size_t len, RSA* rsa){
  if (rsa == NULL) fatal_error();
  return RSA_private_encrypt(len, src, out_buf, rsa, RSA_PKCS1_OAEP_PADDING); //Noncompliant
}

In this example, the function RSA_private_encrypt performs a signature operation by using the OAEP padding scheme, which supports encryption operations only.

Correction — Use Padding Scheme That Supports Signature

One possible correction is to use the RSA-PSS padding scheme. The corrected example uses the function RSA_padding_add_PKCS1_PSS to associate the padding scheme with the context.

#include <stddef.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *msg_pad;
unsigned char *out_buf;

int func(unsigned char *src, size_t len, RSA* rsa){
  if (rsa == NULL) fatal_error(); 

  ret = RSA_padding_add_PKCS1_PSS(rsa, msg_pad, src, EVP_sha256(), -2); 
  if (ret <= 0) fatal_error();

  return RSA_private_encrypt(len, msg_pad, out_buf, rsa, RSA_NO_PADDING); 
}
Issue

This issue occurs when you initialize a context object with a key for a specific algorithm but perform an operation that the algorithm does not support.

For instance, you initialize the context with a key for the DSA algorithm.

ret = EVP_PKEY_set1_DSA(pkey,dsa);
ctx = EVP_PKEY_CTX_new(pkey, NULL);
However, you use the context for encrypting data, an operation that the DSA algorithm does not support.
ret = EVP_PKEY_encrypt(ctx,out, &out_len, in, in_len);

Risk

If the algorithm does not support your cryptographic operation, you do not see the expected results. For instance, if you use the DSA algorithm for encryption, you might get unexpected ciphertext.

Fix

Use the algorithm that is appropriate for the cryptographic operation that you want to perform:

  • Diffie-Hellman (DH): For key derivation.

  • Digital Signature Algorithm (DSA): For signature.

  • RSA: For encryption and signature.

  • Elliptic curve (EC): For key derivation and signature.

Example — Encryption with DSA Algorithm
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len, DSA * dsa){
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *pkey = NULL;

  pkey = EVP_PKEY_new();
  if(pkey == NULL) fatal_error();

  ret = EVP_PKEY_set1_DSA(pkey,dsa);
  if (ret <= 0) fatal_error();

  ctx = EVP_PKEY_CTX_new(pkey, NULL); 
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_encrypt_init(ctx); 
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf, &out_len, src, len);   //Noncompliant
}

In this example, the context object is initialized with a key associated with the DSA algorithm. However, the object is used for encryption, an operation that the DSA algorithm does not support.

Correction — Use RSA Algorithm

One possible correction is to initialize the context object with a key associated with the RSA algorithm.

#include <openssl/evp.h>
#include <openssl/rsa.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len, RSA * rsa){
  EVP_PKEY_CTX *ctx;
  EVP_PKEY *pkey = NULL;

  pkey = EVP_PKEY_new();
  if(pkey == NULL) fatal_error();

  ret = EVP_PKEY_set1_RSA(pkey,rsa);
  if (ret <= 0) fatal_error();

  ctx = EVP_PKEY_CTX_new(pkey, NULL); /* RSA key is set in the context */
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_encrypt_init(ctx); /* Encryption operation is set in the context */
  if (ret <= 0) fatal_error();
  ret = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf, &out_len, src, len);  
}
Issue

This issue occurs when you do not enable blinding for an RSA context object before using the object for decryption or signature verification.

For instance, you do not turn on blinding in the context object rsa before this decryption step:

  ret = RSA_public_decrypt(in_len, in, out, rsa, RSA_PKCS1_PADDING)

Risk

Without blinding, the time it takes for the cryptographic operation to be completed has a correlation with the key value. An attacker can gather information about the RSA key by measuring the time for completion. Blinding removes this correlation and protects the decryption or verification operation against timing attacks.

Fix

Before performing RSA decryption or signature verification, enable blinding.

ret = RSA_blinding_on(rsa, NULL);
Example — Blinding Disabled Before Decryption
#include <stddef.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
int func(unsigned char *src, size_t len, RSA* rsa){
  if (rsa == NULL) fatal_error();

  RSA_blinding_off(rsa);
  return RSA_private_decrypt(len, src, out_buf, rsa, RSA_PKCS1_OAEP_PADDING); //Noncompliant
}

In this example, blinding is disabled for the context object rsa. Decryption with this context object can be vulnerable to timing attacks.

Correction — Enable Blinding Before Decryption

One possible correction is to explicitly enable blinding before decryption. Even if blinding might be enabled previously or by default, explicitly enabling blinding ensures that the security of the current decryption step is not reliant on the caller of func.

#include <stddef.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
int func(unsigned char *src, size_t len, RSA* rsa){
  if (rsa == NULL) fatal_error();

  ret = RSA_blinding_on(rsa, NULL);
  if (ret <= 0) fatal_error();
  return RSA_private_decrypt(len, src, out_buf, rsa, RSA_PKCS1_OAEP_PADDING);
}
Issue

This issue occurs when you do not assign a cipher algorithm when setting up your cipher context.

You can initialize your cipher context without an algorithm. However, before you encrypt or decrypt your data, you must associate the cipher context with a cipher algorithm.

Risk

A missing cipher algorithm can lead to run-time errors or at least, non-secure ciphertext.

Before encryption or decryption, you set up a cipher context that has the information required for encryption: the cipher algorithm and mode, an encryption or decryption key and an initialization vector (for modes that require initialization vectors).

ret = EVP_EncryptInit(&ctx, EVP_aes_128_cbc(), key, iv)
The function EVP_aes_128_cbc() specifies that the Advanced Encryption Standard (AES) algorithm must be used for encryption. The function also specifies a block size of 128 bits and the Cipher Bloch Chaining (CBC) mode.

Instead of specifying the algorithm, you can use NULL in the initialization step. However, before using the cipher context for encryption or decryption, you must perform an additional initialization that associates an algorithm with the context. Otherwise, the update steps for encryption or decryption can lead to run-time errors.

Fix

Before your encryption or decryption steps

 ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len)
associate your cipher context ctx with an algorithm.
ret = EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv)

Example — Algorithm Missing During Context Initialization

#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16

unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(void) {
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();       
    EVP_CIPHER_CTX_init(ctx);
    EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);  //Noncompliant
}

In this example, an algorithm is not provided when the cipher context ctx is initialized.

Before you encrypt or decrypt your data, you have to provide a cipher algorithm. If you perform a second initialization to provide the algorithm, the cipher context is completely re-initialized. Therefore, the current initialization statement using EVP_EncryptInit_ex is redundant.

Correction — Provide Algorithm During Initialization

One possible correction is to provide an algorithm when you initialize the cipher context. In the corrected code below, the routine EVP_aes_128_cbc invokes the Advanced Encryption Standard (AES) algorithm. The routine also specifies a block size of 128 bits and the Cipher Block Chaining (CBC) mode for encryption.


#include <openssl/evp.h>
#include <stdlib.h>
#define SIZE16 16

unsigned char key[SIZE16];
unsigned char iv[SIZE16];
void func(unsigned char *src, int len, unsigned char *out_buf, int out_len) {
    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();       
    EVP_CIPHER_CTX_init(ctx);
    
    /* Initialization of cipher context */
    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); 
    
    /* Update steps for encryption */
    EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
}
Issue

This issue occurs when you encrypt or decrypt data using a NULL encryption or decryption key.

Note

You can initialize your cipher context with a NULL key. However, before you encrypt or decrypt your data, you must associate the cipher context with a non-NULL key.

Risk

Encryption or decryption with a NULL key can lead to run-time errors or at least, non-secure ciphertext.

Fix

Before your encryption or decryption steps

 ret = EVP_EncryptUpdate(&ctx, out_buf, &out_len, src, len)
associate your cipher context ctx with a non-NULL key.
ret = EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)

Sometimes, you initialize your cipher context with a non-NULL key

ret = EVP_EncryptInit_ex(&ctx, cipher_algo_1, NULL, key, iv)
but change the cipher algorithm later. When you change the cipher algorithm, you use a NULL key.
 ret = EVP_EncryptInit_ex(&ctx, cipher_algo_2, NULL, NULL, NULL)
The second statement reinitializes the cipher context completely but with a NULL key. To avoid this issue, every time you initialize a cipher context with an algorithm, associate it with a key.

Example — NULL Key Used for Encryption

#include <openssl/evp.h>
#include <stdlib.h>
#define fatal_error() abort()

unsigned char *out_buf;
int out_len;

int func(EVP_CIPHER_CTX *ctx, unsigned char *iv, unsigned char *src, int len){
    if (iv == NULL)
        fatal_error();
    
    /* Fourth argument is cipher key */
    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, iv); 
    
    /* Update step with NULL key */
    return EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len); //Noncompliant
}

In this example, the cipher key associated with the context ctx is NULL. When you use this context to encrypt your data, you can encounter run-time errors.

Correction — Use Random Cipher Key

Use a strong random number generator to produce the cipher key. The corrected code here uses the function RAND_bytes declared in openssl/rand.h.


#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdlib.h>
#define fatal_error() abort()
#define SIZE16 16

unsigned char *out_buf;
int out_len;

int func(EVP_CIPHER_CTX *ctx, unsigned char *iv, unsigned char *src, int len){
    if (iv == NULL)
        fatal_error();
    unsigned char key[SIZE16];
    RAND_bytes(key, 16);
    
    /* Fourth argument is cipher key */
    EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); 
    
    /* Update step with non-NULL cipher key */
    return EVP_EncryptUpdate(ctx, out_buf, &out_len, src, len);
}
Issue

This issue occurs when the data provided for an encryption, decryption, signing, or authentication operation is NULL or the data length is zero.

For instance, you unintentionally provide a NULL value for in or a zero value for in_len in this decryption operation:

ret = EVP_PKEY_decrypt(ctx, out, &out_len, in, in_len);
Or, you provide a NULL value for md or sig, or a zero value for md_len or sig_len in this verification operation:
ret = EVP_PKEY_verify(ctx, md, mdlen, sig, siglen);

Risk

With NULL data or zero length, the operation does not occur. The redundant operation often indicates a coding error.

Fix

Check the placement of the encryption, decryption, or signing operation. If the operation is intended to happen, make sure that the data provided is non-NULL. Set the data length to a nonzero value.

Example — Zero Data Length for Signing Operation
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
int func(EVP_PKEY_CTX * ctx){
  if (ctx == NULL) fatal_error(); 
  unsigned char* sig = (unsigned char*) "0123456789";
  unsigned char* md = (unsigned char*) "0123456789";

  ret = EVP_PKEY_verify_init(ctx);
  if (ret <= 0) fatal_error();
  ret = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256());
  if (ret <= 0) fatal_error();
  return EVP_PKEY_verify(ctx, sig, 0, md, 0);  //Noncompliant
}

In this example, the data lengths (third and fifth arguments to EVP_PKEY_verify) are zero. The operation fails.

Correction — Use Nonzero Data Length

One possible correction is to use a nonzero length for the signature and the data believed to be signed.

#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
int func(EVP_PKEY_CTX * ctx){
  if (ctx == NULL) fatal_error(); 
  unsigned char* sig = (unsigned char*) "0123456789";
  unsigned char* md = (unsigned char*) "0123456789";

  ret = EVP_PKEY_verify_init(ctx);
  if (ret <= 0) fatal_error();
  ret = EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256());
  if (ret <= 0) fatal_error();
  return EVP_PKEY_verify(ctx, sig, 10, md, 10); 
}
Issue

The issue occurs when, after an update operation on a message digest context, you do not perform a final step before you clean up or reinitialize the context.

When you use message digest functions, you typically initialize a message digest context and perform at least one update step to add data into the context. You then sign, verify, or retrieve the data in the context as a final step.

Risk

A missing final step might indicate that the hash is incomplete or is non-secure.

Fix

Perform a final step to sign, verify, or retrieve date from the message digest context before you clean up or reinitialize the context.

Example — Missing Final Step Before Context Cleanup

#include <stdlib.h>
#include <openssl/evp.h>


void func(unsigned char* src, int len, EVP_PKEY* pkey)
{
    int ret;

    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    ret = EVP_DigestVerifyInit(&ctx, NULL, EVP_sha256(), NULL, pkey);
    if (ret != 1) handle_error();

    ret = EVP_DigestVerifyUpdate(&ctx, src, len);
    if (ret != 1) handle_error();

    EVP_MD_CTX_cleanup(&ctx); //Noncompliant
}

In this example, a verification context ctx is initialized and updated with data. The context is then cleaned up without being verified in a final step. Typically, you create a verification context to validate a previously signed message. Without the final step the signature on the message cannot be validated.

Correction — Perform Final Step Before Context Cleanup

One possible correction is to perform a final step to verify the signature of the verification context before you clean up the context.


#include <stdlib.h>
#include <openssl/evp.h>

unsigned char out_buf[EVP_MAX_MD_SIZE];
unsigned int out_len;

void handle_error()
{
    exit(-1);
}


void func(unsigned char* src, int len, EVP_PKEY* pkey)
{
    int ret;

    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    ret = EVP_DigestVerifyInit(&ctx, NULL, EVP_sha256(), NULL, pkey);
    if (ret != 1) handle_error();

    ret = EVP_DigestVerifyUpdate(&ctx, src, len);
    if (ret != 1) handle_error();

    ret = EVP_DigestVerifyFinal(&ctx, out_buf, out_len);
    if (ret != 1) handle_error();

    EVP_MD_CTX_cleanup(&ctx);
} 
Issue

This issue occurs when you use a message digest context in these EVP routines, but you initialize the context without specifying a hash algorithm.

  • EVP_DigestFinal

  • EVP_DigestSignFinal

  • EVP_SignFinal

  • EVP_VerifyFinal

Risk

Using a message digest context that was initialized without an algorithm to perform a hashing operation might result in a run-time error. Even if the hashing operation is successful, the resulting digest is not secure.

Fix

Specify a hash algorithm when you initial a message digest context that you use in an EVP routine.

Example — Context Used in EVP Routine After Context Cleanup

#include <openssl/evp.h>

void func(unsigned char* src, int len)
{
    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    EVP_VerifyInit(&ctx, EVP_sha256());
    EVP_MD_CTX_cleanup(&ctx);
    EVP_VerifyUpdate(&ctx, src, len); //Noncompliant
}

In this example, context ctx is initialized with secure hash algorithm SHA-256. But, ctx is cleaned up before it is used by EVP_VerifyUpdate. The clean up of ctx frees up its resources and reinitializes it without a hash algorithm. The hashing operation of EVP_VerifyUpdate might result in a run-time error.

Correction — Clean Up Context Only After You No Longer Need It

One possible correction is to clean up the digest context only after you no longer need it.

Issue

This issue occurs when you perform a key generation step with a context object without first associating the object with required parameters.

For instance, you associate a EVP_PKEY_CTX context object with an empty EVP_PKEY object params before key generation :

EVP_PKEY * params = EVP_PKEY_new();
...
EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new(params, NULL);
... 
EVP_PKEY_keygen(ctx, &pkey);

Risk

Without appropriate parameters, the key generation step does not occur. The redundant operation often indicates a coding error.

Fix

Check the placement of the key generation step. If the operation is intended, make sure that the parameters are set before key generation.

Certain algorithms use default parameters. For instance, if you specify the DSA algorithm when creating the EVP_PKEY_CTX object, a default key length of 1024 bits is used:

kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_DSA, NULL);
Specifying the algorithm during context creation is sufficient to avoid this defect. Only if you use the Elliptic Curve (EC) algorithm, you must also specify the curve explicitly before key generation.

However, the default parameters can generate keys that are too weak for encryption. Weak parameters can trigger another defect. To change default parameters, use functions specific to the algorithm. For instance, to set parameters, you can use these functions:

  • Diffie-Hellman (DH): Use EVP_PKEY_CTX_set_dh_paramgen_prime_len and EVP_PKEY_CTX_set_dh_paramgen_generator.

  • Digital Signature Algorithm (DSA): Use EVP_PKEY_CTX_set_dsa_paramgen_bits.

  • RSA: Use EVP_PKEY_CTX_set_rsa_padding, EVP_PKEY_CTX_set_rsa_pss_saltlen, EVP_PKEY_CTX_set_rsa_rsa_keygen_bits, and EVP_PKEY_CTX_set_rsa_keygen_pubexp.

  • Elliptic curve (EC): Use EVP_PKEY_CTX_set_ec_paramgen_curve_nid and EVP_PKEY_CTX_set_ec_param_enc.

Example — Empty Parameters During Key Generation
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
int func(EVP_PKEY *pkey){
  EVP_PKEY * params = EVP_PKEY_new();
  if (params == NULL) fatal_error();

  EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new(params, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_keygen_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_keygen(ctx, &pkey); //Noncompliant
}

In this example, the context object ctx is associated with an empty parameter object params. The context object does not have the required parameters for key generation.

Correction — Specify Algorithm During Context Creation

One possible correction is to specify an algorithm, such as RSA, during context creation. For stronger encryption, use 2048 bits for key length instead of the default 1024 bits.

#include <openssl/evp.h>
#include <openssl/rsa.h>

#define fatal_error() exit(-1)

int ret;
int func(EVP_PKEY *pkey){
  EVP_PKEY_CTX * ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL); 
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_keygen_init(ctx);
  if (ret <= 0) fatal_error();
  
  ret = EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, 2048); 
  if (ret <= 0) fatal_error();
  
  return EVP_PKEY_keygen(ctx, &pkey); 
}
Issue

This issue occurs when you use a context object for shared secret derivation but you have not previously associated the object with a non-NULL peer key.

For instance, you initialize the context object, and then use the object for shared secret derivation without an intermediate step where the object is associated with a peer key:

EVP_PKEY_derive_init(ctx);
/* Missing step for associating peer key with context */
ret = EVP_PKEY_derive(ctx, out_buf, &out_len);

The counterpart checker Missing private key checks for a private key in shared secret derivation.

Risk

Without a peer key, the shared secret derivation step does not occur. The redundant operation often indicates a coding error.

Fix

Check the placement of the shared secret derivation step. If the operation is intended, make sure that you have completed these steps prior to the operation:

  • Generate a non-NULL peer key.

    For instance:

    EVP_PKEY* peerkey = NULL;
    EVP_PKEY_keygen(EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL), &peerkey);

  • Associate a non-NULL context object with the peer key.

    For instance:

    EVP_PKEY_derive_set_peer(ctx,peerkey);
    

Example — Missing Step for Associating Peer Key with Context
#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(EVP_PKEY *pkey){
  if (pkey == NULL) fatal_error(); 

  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); 
  if (ctx == NULL) fatal_error();
  ret = EVP_PKEY_derive_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_derive(ctx, out_buf, &out_len);  //Noncompliant
}

In this example, the context object ctx is associated with a private key but not a peer key. The EVP_PKEY_derive function uses this context object for shared secret derivation.

Correction — Set Peer Key in Context

One possible correction is to use the function EVP_PKEY_derive_set_peer and associate a peer key with the context object. Make sure that the peer key is non-NULL.

#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(EVP_PKEY *pkey,  EVP_PKEY* peerkey){
  if (pkey == NULL) fatal_error(); 
  if (peerkey == NULL) fatal_error(); 
  
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL); 
  if (ctx == NULL) fatal_error();
  ret = EVP_PKEY_derive_init(ctx);
  if (ret <= 0) fatal_error();
  ret = EVP_PKEY_derive_set_peer(ctx,peerkey); 
  if (ret <= 0) fatal_error();
  return EVP_PKEY_derive(ctx, out_buf, &out_len); 
}
Issue

This issue occurs when you use a context object for decryption, signature, or shared secret derivation but you have not previously associated the object with a non-NULL private key.

For instance, you initialize the context object with a NULL private key and use the object for decryption later.

ctx = EVP_PKEY_CTX_new(pkey, NULL);
...
ret = EVP_PKEY_decrypt_init(ctx);
...
ret = EVP_PKEY_decrypt(ctx, out, &out_len, in, in_len);

The counterpart checker Missing public key checks for a public key in encryption and authentication operations. The checker Missing peer key checks for a peer key in shared secret derivation.

Risk

Without a private key, the decryption, signature, or shared secret derivation step does not occur. The redundant operation often indicates a coding error.

Fix

Check the placement of the operation (decryption, signature, or shared secret derivation). If the operation is intended, make sure you have completed these steps prior to the operation:

  • Generate a non-NULL private key.

    For instance:

    EVP_PKEY *pkey = NULL;
    kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    
    EVP_PKEY_keygen_init(kctx);
    EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, RSA_2048BITS);
    EVP_PKEY_keygen(kctx, &pkey);

  • Associate a non-NULL context object with the private key.

    For instance:

    ctx = EVP_PKEY_CTX_new(pkey, NULL);
    

    Note: If you use EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new, you are not associating the context object with a private key.

Example — Missing Step for Associating Private Key with Context
#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len){
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_decrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_decrypt(ctx, out_buf, &out_len, src, len);  //Noncompliant
}

In this example, the context object ctx is initialized with EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new. The function EVP_PKEY_CTX_new_id does not associate the context object with a key. However, the EVP_PKEY_decrypt function uses this object for decryption.

Correction — Associate Private Key with Context During Initialization

One possible correction is to use the EVP_PKEY_CTX_new function for context initialization and associate a private key with the context object. In the following correction, the private key pkey is obtained from an external source and checked for NULL before use.

#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len, EVP_PKEY *pkey){
  if (pkey == NULL) fatal_error(); 
  
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_decrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_decrypt(ctx, out_buf, &out_len, src, len); 
}

Issue

The issue occurs when you load a X.509 certificate file into the SSL context but you do not load the corresponding private key, or the key that you load into the context is null.

Typically, in a TLS/SSL exchange, the server proves its identity during a TLS/SSL handshake by sending a X.509 certificate that contains information about the server and a public key. The client that receives the certificate uses the public key to encrypt and send a pre-master secret that can only be decrypted with the corresponding private key. The server uses the decrypted pre-master secret and other exchanged messages to generate session keys that are used to encrypt the communication session.

The checker raises no defect if:

  • You pass the SSL context as an argument to the function that calls SSL_new.

  • You declare the SSL context outside the scope of the function handling the connection.

Risk

Not loading the private key for a X.509 certificate might result in a run-time error on non-secure encryption.

Fix

Load the private key of the X.509 certificate into the SSL context by calling SSL_CTX_use_PrivateKey_file or load the private key into the SSL structure by calling SSL_use_PrivateKey_file.

Example — No Private Key Loaded Into SSL Context
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#define SSL_SERVER_CRT "server.pem"

#define fatal_error() exit(-1)

void load_cert(SSL_CTX* ctx, const char* certfile)
{
    int ret = SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM);
    if (ret <= 0) fatal_error();
}

void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;

    /* creation context for the SSL protocol */
    ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) fatal_error();

    /* context configuration */
    load_cert(ctx, SSL_SERVER_CRT);

    /* Handle connection */
    ssl = SSL_new(ctx);
    ret = SSL_accept(ssl); //Noncompliant
    if (ret <= 0) fatal_error();

    SSL_free(ssl);
    SSL_CTX_free(ctx);
}

In this example, SSL context ctx is initiated with server role and the function load_cert loads the server certificate into ctx. The server then waits for a client to initiate a handshake. However, since the private key is not loaded into the SSL structure, the server cannot decrypt the pre-master secret that a client sends, and the handshake fails.

Correction — Load Private Key into SSL Context

One possible correction is to load the private key into the SSL context after you load the server certificate file.

#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>
#define SSL_SERVER_CRT "server.pem"
#define SSL_SERVER_KEY "server.key"

#define fatal_error() exit(-1)

void load_cert(SSL_CTX* ctx, const char* certfile)
{
    int ret = SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM);
    if (ret <= 0) fatal_error();

    ret = SSL_CTX_use_PrivateKey_file(ctx, SSL_SERVER_KEY, SSL_FILETYPE_PEM);
    if (ret <= 0) fatal_error();
}

void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;

    /* creation context for the SSL protocol */
    ctx = SSL_CTX_new(SSLv23_server_method());
    if (ctx == NULL) fatal_error();

    /* context configuration */
    load_cert(ctx, SSL_SERVER_CRT);

    /* Handle connection */
    ssl = SSL_new(ctx);
    ret = SSL_accept(ssl);
    if (ret <= 0) fatal_error();

    SSL_free(ssl);
    SSL_CTX_free(ctx);
}
Issue

This issue occurs when you use a context object for encryption or signature authentication but you have not previously associated the object with a non-NULL public key.

For instance, you initialize the context object with a NULL public key and use the object for encryption later.

ctx = EVP_PKEY_CTX_new(pkey, NULL);
...
ret = EVP_PKEY_encrypt_init(ctx);
...
ret = EVP_PKEY_encrypt(ctx, out, &out_len, in, in_len);

The counterpart checker Missing private key checks for a private key in decryption and signature operations.

Risk

Without a public key, the encryption or signature authentication step does not happen. The redundant operation often indicates a coding error.

Fix

Check the placement of the operation (encryption or signature authentication). If the operation is intended to happen, make sure you have done these steps prior to the operation:

  • You generated a non-NULL public key.

    For instance:

    EVP_PKEY *pkey = NULL;
    kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    
    EVP_PKEY_keygen_init(kctx);
    EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, RSA_2048BITS);
    EVP_PKEY_keygen(kctx, &pkey);

  • You associated a non-NULL context object with the public key.

    For instance:

    ctx = EVP_PKEY_CTX_new(pkey, NULL);
    

    Note: If you use EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new, you are not associating the context object with a public key.

Example — Missing Step for Associating Private Key with Context
#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len){
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_encrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf, &out_len, src, len);  //Noncompliant
}

In this example, the context object ctx is initialized with EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new. The function EVP_PKEY_CTX_new_id does not associate the context object with a key. However, the EVP_PKEY_encrypt function uses this object for decryption.

Correction — Associate Public Key with Context During Initialization

One possible correction is to use the EVP_PKEY_CTX_new function for context initialization and associate a public key with the context object. In the following correction, the public key pkey is obtained from an external source and checked for NULL before use.

#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len, EVP_PKEY *pkey){
  if (pkey == NULL) fatal_error(); 
  
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_encrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_encrypt(ctx, out_buf, &out_len, src, len); 
}

Issue

This issue occurs when the following happens:

  • A nonreentrant standard function returns a pointer.

  • You attempt to write to the memory location that the pointer points to.

Nonreentrant standard functions that return a non const-qualified pointer to an internal buffer include getenv, getlogin, crypt, setlocale, localeconv, strerror and others.

Risk

Modifying the internal buffer that a nonreentrant standard function returns can cause the following issues:

  • It is possible that the modification does not succeed or alters other internal data.

    For instance, getenv returns a pointer to an environment variable value. If you modify this value, you alter the environment of the process and corrupt other internal data.

  • Even if the modification succeeds, it is possible that a subsequent call to the same standard function does not return your modified value.

    For instance, you modify the environment variable value that getenv returns. If another process, thread, or signal handler calls setenv, the modified value is overwritten. Therefore, a subsequent call to getenv does not return your modified value.

Fix

Avoid modifying the internal buffer using the pointer returned from the function.

Example — Modification of getenv Return Value
#include <stdlib.h>
#include <string.h>

void printstr(const char*);

void func() {
    char* env = getenv("LANGUAGE");
    if (env != NULL) {
        strncpy(env, "C", 1); //Noncompliant
        printstr(env);
    }
}

In this example, the first argument of strncpy is the return value from a nonreentrant standard function getenv. The behavior can be undefined because strncpy modifies this argument.

Correction - Copy Return Value of getenv and Modify Copy

One possible solution is to copy the return value of getenv and pass the copy to the strncpy function.

#include <stdlib.h>
#include <string.h>
enum {
    SIZE20 = 20
};

void printstr(const char*);

void func() {
    char* env = getenv("LANGUAGE");
    if (env != NULL) {
        char env_cp[SIZE20];
        strncpy(env_cp, env, SIZE20);  
        strncpy(env_cp, "C", 1);        
        printstr(env_cp);
    }
}
Issue

The issue occurs when you call one of these functions without explicitly setting the connection method of the TLS/SSL context.

  • SSL_read

  • SSL_write

  • SSL_do_handshake

The communication between server and client entities that use a TLS/SSL connection begins with a handshake. During the handshake, the parties exchange information and establish the encryption algorithm and session keys the parties use during the session. The connection methods for the server and client use different routines for the handshake.

The checker raises no defect if:

  • You use SSL_connect (client) and SSL_accept (server) functions. These functions set the correct handshake routines automatically.

  • You pass the SSL context as an argument to the function that calls SSL_new.

  • You declare the SSL context outside the scope of the function handling the connection.

Risk

You cannot begin a handshake if the SSL engine does not know which connection method routines to call.

Fix
  • For client handshake routines, call SSL_set_connect_state before you begin the handshake.

  • For server handshake routines, call SSL_set_accept_state before you begin the handshake.

Example — Server Connection Method Not Set Explicitly
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>

#define fatal_error() exit(-1)

int len;
unsigned char buf;
volatile int rd;

const SSL_METHOD*  set_method()
{
    return SSLv23_server_method();
}

void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;
    const SSL_METHOD* method =  set_method();
    ctx = SSL_CTX_new(method);
    ssl = SSL_new(ctx);

    switch (rd) {
    case 1:
        ret = SSL_read(ssl, (void*)buf, len); //Noncompliant  
        if (ret <= 0) fatal_error();
        break;
    case 2:
        ret = SSL_do_handshake(ssl); //Noncompliant 
        if (ret <= 0) fatal_error();
        break;
    default:
        ret = SSL_write(ssl, (void*)buf, len); //Noncompliant 
        if (ret <= 0) fatal_error();
        break;
    }
}

In this example, the SSL context ctx is generated with server connection method SSLv23_server_method. However, the connection method is not set explicitly for the SSL structure ssl before the attempt to read from the connection, initiate a handshake, or write to the connection.

Correction — Set Server Connection Method Explicitly

One possible correction is to call SSL_set_accept_state to set the server role for the SSL structure ssl before you begin the handshake.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>

#define fatal_error() exit(-1)

int len;
unsigned char buf;
volatile int rd;

const SSL_METHOD* set_method()
{
    return SSLv23_server_method();
}

void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;
    const SSL_METHOD* method = set_method();
    ctx = SSL_CTX_new(method);
    if (ctx == NULL) fatal_error();

    // Load the server's certificate and private key
    if (SSL_CTX_use_certificate_file(ctx, "server.crt", SSL_FILETYPE_PEM) <= 0) fatal_error();
    if (SSL_CTX_use_PrivateKey_file(ctx, "server.key", SSL_FILETYPE_PEM) <= 0) fatal_error();

    ssl = SSL_new(ctx);
    if (ssl == NULL) fatal_error();
    
    SSL_set_accept_state(ssl);

    switch (rd) {
    case 1:
        ret = SSL_read(ssl, (void*)buf, len);
        if (ret <= 0) fatal_error();
        break;
    case 2:
        ret = SSL_do_handshake(ssl);
        if (ret <= 0) fatal_error();
        break;
    default:
        ret = SSL_write(ssl, (void*)buf, len);
        if (ret <= 0) fatal_error();
        break;
    }

    // Clean up
    SSL_free(ssl);
    SSL_CTX_free(ctx);
} 
Issue

The issue occurs when you call functions that do not match the role set by the connection method that you specified for the SSL context.

The functions that you call when handling a TLS/SSL connection between client and server entities are different, depending on the role of the entity. For instance, the connection between a server and a client begins with a handshake. The client always initiates the handshake. You use SSL_accept with a server entity to wait for a client to initiate the handshake.

Typically, you set a connection method when you initiate the SSL context. The method specifies the role of the entity.

The checker flags the use of functions that do not match the connection method specified for the SSL context. See the Event column in the Results Details pane to view connection method specified for the SSL context.

Risk

If you set the TLS/SSL connection method incorrectly, the functions you use to handle the connection might not match the role specified by the method. For instance, you use SSL_accept with a client entity to wait for a client to initiate a handshake instead of SSL_connect to initiate the handshake with a server.

Fix

Make sure that you use functions that match the TLS/SSL connection method to handle the connection.

Example — Client Waiting for Client to Initiate Handshake
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>

#define fatal_error() exit(-1)

const SSL_METHOD*  set_method()
{
    return SSLv23_client_method();
}

void set_method_1(SSL* ssl)
{
    SSL_set_connect_state(ssl);
}
void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;
    const SSL_METHOD* method = set_method();
    ctx = SSL_CTX_new(method);
    ssl = SSL_new(ctx);
    set_method_1(ssl);
    ret = SSL_accept(ssl); //Noncompliant 
    if (ret <= 0) fatal_error();
}

In this example, the SSL context ctx is initialized with a client role. The SSL structure is also explicitly set to client role through the call to set_method_1. To establish a connection with the server, the client should initiate a handshake with the server. Instead, SSL_accept causes the client to wait for another client to initiate a handshake.

Correction — Use SSL_connect to Initiate Handshake with Server

One possible correction is to use SSL_connect to initiate the TLS/SSL handshake with the server.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/ssl.h>

#define fatal_error() exit(-1)

const SSL_METHOD*  set_method()
{
    return SSLv23_client_method();
}

void set_method_1(SSL* ssl)
{
    SSL_set_connect_state(ssl);
}
void func()
{
    int ret;
    SSL_CTX* ctx;
    SSL* ssl;
    const SSL_METHOD* method = set_method();
    ctx = SSL_CTX_new(method);
    ssl = SSL_new(ctx);
    set_method_1(ssl);
    ret = SSL_connect(ssl);
    if (ret <= 0) fatal_error();
} 

Check Information

Category: Others

Version History

Introduced in R2024a