コード例 #1
0
my_bool ma_schannel_verify_certs(SC_CTX *sctx, DWORD dwCertFlags)
{
  SECURITY_STATUS sRet;
  DWORD flags;
  MARIADB_PVIO *pvio= sctx->mysql->net.pvio;
  PCCERT_CONTEXT pServerCert= NULL;

  if ((sRet= QueryContextAttributes(&sctx->ctxt, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (PVOID)&pServerCert)) != SEC_E_OK)
  {
    ma_schannel_set_sec_error(pvio, sRet);
    return 0;
  }

  flags= CERT_STORE_SIGNATURE_FLAG |
         CERT_STORE_TIME_VALIDITY_FLAG;


    
  if (sctx->client_ca_ctx)
  {
 	  if (!(sRet= CertVerifySubjectCertificateContext(pServerCert,
                                                    sctx->client_ca_ctx,
                                                    &flags)))
    {
      ma_schannel_set_win_error(pvio);
      return 0;
    }

    if (flags)
    {
      if ((flags & CERT_STORE_SIGNATURE_FLAG) != 0)
        pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Certificate signature check failed");
      else if ((flags & CERT_STORE_REVOCATION_FLAG) != 0)
        pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate was revoked");
      else if ((flags & CERT_STORE_TIME_VALIDITY_FLAG) != 0)
        pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "certificate has expired");
      else
        pvio->set_error(sctx->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Unknown error during certificate validation");
      return 0;
    }
  }

  /* Check if none of the certificates in the certificate chain have been revoked. */
  if (sctx->client_crl_ctx)
  {
    PCRL_INFO Info[1];

    Info[0]= sctx->client_crl_ctx->pCrlInfo;
    if (!(CertVerifyCRLRevocation(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                  pServerCert->pCertInfo,
                                  1, Info))                               )
    {
      pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "CRL Revocation failed");
      return 0;
    }
  }
  return 1;
}
コード例 #2
0
/*
  Create a crl context from crlfile

  SYNOPSIS
    ma_schannel_create_crl_context()
    pem_file               name of certificate or ca file

  DESCRIPTION
    Loads a certification revocation list file, creates a certification
    context and loads the binary representation into crl context.
    The returned context must be freed by caller.
    If the function failed, error can be retrieved by GetLastError().

  RETURNS
    NULL                   If loading of the file or creating context failed
    PCCRL_CONTEXT          A pointer to a certification context structure
*/
PCCRL_CONTEXT ma_schannel_create_crl_context(MARIADB_PVIO *pvio, const char *pem_file)
{
  DWORD der_buffer_length;
  LPBYTE der_buffer= NULL;

  PCCRL_CONTEXT ctx= NULL;

  /* load ca pem file into memory */
  if (!(der_buffer= ma_schannel_load_pem(pvio, pem_file, (DWORD *)&der_buffer_length)))
    goto end;
  if (!(ctx= CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                    der_buffer, der_buffer_length)))
    ma_schannel_set_win_error(pvio);
end:
  if (der_buffer)
    LocalFree(der_buffer);
  return ctx;
}
コード例 #3
0
/*
  Create a certification context from ca or cert file

  SYNOPSIS
    ma_schannel_create_cert_context()
    pvio                    pvio object
    pem_file               name of certificate or ca file

  DESCRIPTION
    Loads a PEM file (certificate authority or certificate) creates a certification
    context and loads the binary representation into context.
    The returned context must be freed by caller.
    If the function failed, error can be retrieved by GetLastError().

  RETURNS
    NULL                   If loading of the file or creating context failed
    CERT_CONTEXT *         A pointer to a certification context structure
*/
CERT_CONTEXT *ma_schannel_create_cert_context(MARIADB_PVIO *pvio, const char *pem_file)
{
  DWORD der_buffer_length;
  LPBYTE der_buffer= NULL;

  CERT_CONTEXT *ctx= NULL;

  /* create DER binary object from ca/certification file */
  if (!(der_buffer= ma_schannel_load_pem(pvio, pem_file, (DWORD *)&der_buffer_length)))
    goto end;
  if (!(ctx= (CERT_CONTEXT *)CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                                    der_buffer, der_buffer_length)))
    ma_schannel_set_win_error(pvio);

end:
  if (der_buffer)
    LocalFree(der_buffer);
  return ctx;
}
コード例 #4
0
my_bool ma_schannel_load_private_key(MARIADB_PVIO *pvio, CERT_CONTEXT *ctx, char *key_file)
{
   DWORD der_buffer_len= 0;
   LPBYTE der_buffer= NULL;
   DWORD priv_key_len= 0;
   LPBYTE priv_key= NULL;
   HCRYPTPROV  crypt_prov= 0;
   HCRYPTKEY  crypt_key= 0;
   CERT_KEY_CONTEXT kpi={ 0 };
   my_bool rc= 0;

   /* load private key into der binary object */
   if (!(der_buffer= ma_schannel_load_pem(pvio, key_file, &der_buffer_len)))
     return 0;

   /* determine required buffer size for decoded private key */
   if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                            PKCS_RSA_PRIVATE_KEY,
                            der_buffer, der_buffer_len,
                            0, NULL,
                            NULL, &priv_key_len))
   {
     ma_schannel_set_win_error(pvio);
     goto end;
   }

   /* allocate buffer for decoded private key */
   if (!(priv_key= LocalAlloc(0, priv_key_len)))
   {
     pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
     goto end;
   }

   /* decode */
   if (!CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
                            PKCS_RSA_PRIVATE_KEY,
                            der_buffer, der_buffer_len,
                            0, NULL,
                            priv_key, &priv_key_len))
   {
     ma_schannel_set_win_error(pvio);
     goto end;
   }

   /* Acquire context */
   if (!CryptAcquireContext(&crypt_prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
   {
     ma_schannel_set_win_error(pvio);
     goto end;
   }
   /* ... and import the private key */
   if (!CryptImportKey(crypt_prov, priv_key, priv_key_len, 0, 0, (HCRYPTKEY *)&crypt_key))
   {
     ma_schannel_set_win_error(pvio);
     goto end;
   }

   kpi.hCryptProv= crypt_prov;
   kpi.dwKeySpec = AT_KEYEXCHANGE;
   kpi.cbSize= sizeof(kpi);

   /* assign private key to certificate context */
   if (CertSetCertificateContextProperty(ctx, CERT_KEY_CONTEXT_PROP_ID, 0, &kpi))
     rc= 1;
   else
     ma_schannel_set_win_error(pvio);

end:
  if (der_buffer)
    LocalFree(der_buffer);
  if (priv_key)
  {
    if (crypt_key)
      CryptDestroyKey(crypt_key);
    LocalFree(priv_key);
  if (!rc)
    if (crypt_prov)
      CryptReleaseContext(crypt_prov, 0);
  }
  return rc;
}
コード例 #5
0
/*
   Load a pem or clr file and convert it to a binary DER object

   SYNOPSIS
     ma_schannel_load_pem()
     PemFileName           name of the pem file (in)
     buffer_len            length of the converted DER binary

   DESCRIPTION
     Loads a X509 file (ca, certification, key or clr) into memory and converts
     it to a DER binary object. This object can be decoded and loaded into
     a schannel crypto context.
     If the function failed, error can be retrieved by GetLastError()
     The returned binary object must be freed by caller.

   RETURN VALUE
     NULL                  if the conversion failed or file was not found
     LPBYTE *              a pointer to a binary der object
                           buffer_len will contain the length of binary der object
*/
static LPBYTE ma_schannel_load_pem(MARIADB_PVIO *pvio, const char *PemFileName, DWORD *buffer_len)
{
  HANDLE hfile;
  char   *buffer= NULL;
  DWORD dwBytesRead= 0;
  LPBYTE der_buffer= NULL;
  DWORD der_buffer_length;

  if (buffer_len == NULL)
    return NULL;

  
  if ((hfile= CreateFile(PemFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 
                          FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE)
  {
    ma_schannel_set_win_error(pvio);
    return NULL;
  }

  if (!(*buffer_len = GetFileSize(hfile, NULL)))
  {
     pvio->set_error(pvio->mysql, CR_SSL_CONNECTION_ERROR, SQLSTATE_UNKNOWN, "Invalid pem format");
     goto end;
  }

  if (!(buffer= LocalAlloc(0, *buffer_len + 1)))
  {
    pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
    goto end;
  }

  if (!ReadFile(hfile, buffer, *buffer_len, &dwBytesRead, NULL))
  {
    ma_schannel_set_win_error(pvio);
    goto end;
  }

  CloseHandle(hfile);

  /* calculate the length of DER binary */
  if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
                            NULL, &der_buffer_length, NULL, NULL))
  {
    ma_schannel_set_win_error(pvio);
    goto end;
  }
  /* allocate DER binary buffer */
  if (!(der_buffer= (LPBYTE)LocalAlloc(0, der_buffer_length)))
  {
    pvio->set_error(pvio->mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, NULL);
    goto end;
  }
  /* convert to DER binary */
  if (!CryptStringToBinaryA(buffer, *buffer_len, CRYPT_STRING_BASE64HEADER,
                            der_buffer, &der_buffer_length, NULL, NULL))
  {
    ma_schannel_set_win_error(pvio);
    goto end;
  }

  *buffer_len= der_buffer_length;
  LocalFree(buffer);
  
  return der_buffer;

end:
  if (hfile != INVALID_HANDLE_VALUE)
    CloseHandle(hfile);
  if (buffer)
    LocalFree(buffer);
  if (der_buffer)
    LocalFree(der_buffer);
  *buffer_len= 0;
  return NULL;
}
コード例 #6
0
/* {{{ static int ma_tls_set_client_certs(MARIADB_TLS *ctls) */
static int ma_tls_set_client_certs(MARIADB_TLS *ctls)
{
  MYSQL *mysql= ctls->pvio->mysql;
  char *certfile= mysql->options.ssl_cert,
       *keyfile= mysql->options.ssl_key,
       *cafile= mysql->options.ssl_ca;
  PCERT_CONTEXT ca_ctx= NULL;
  PCRL_CONTEXT crl_ctx = NULL;
       
  SC_CTX *sctx= (SC_CTX *)ctls->ssl;
  MARIADB_PVIO *pvio= ctls->pvio;

  if (cafile)
  {
    if (!(ca_ctx = ma_schannel_create_cert_context(pvio, cafile)))
      goto end;

    /* Add ca to in-memory certificate store */
    if (CertAddCertificateContextToStore(ca_CertStore, ca_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
        GetLastError() != CRYPT_E_EXISTS)
    {
      ma_schannel_set_win_error(sctx->mysql);
      goto end;
    }
    ca_Check= 0;
    CertFreeCertificateContext(ca_ctx);
  }

  if (!certfile && keyfile)
    certfile= keyfile;
  if (!keyfile && certfile)
    keyfile= certfile;

  if (certfile && certfile[0])
    if (!(sctx->client_cert_ctx = ma_schannel_create_cert_context(ctls->pvio, certfile)))
      goto end;

  if (sctx->client_cert_ctx && keyfile[0])
    if (!ma_schannel_load_private_key(pvio, sctx->client_cert_ctx, keyfile))
      goto end;
 
  if (mysql->options.extension && mysql->options.extension->ssl_crl)
  {
    if (!(crl_ctx= (CRL_CONTEXT *)ma_schannel_create_crl_context(pvio, mysql->options.extension->ssl_crl)))
      goto end;
    /* Add ca to in-memory certificate store */
    if (CertAddCRLContextToStore(crl_CertStore, crl_ctx, CERT_STORE_ADD_NEWER, NULL) != TRUE &&
        GetLastError() != CRYPT_E_EXISTS)
    {
      ma_schannel_set_win_error(sctx->mysql);
      goto end;
    }
    crl_Check = 1;
    CertFreeCertificateContext(ca_ctx);
  }
  return 0;
  
end:
  if (ca_ctx)
    CertFreeCertificateContext(ca_ctx);
  if (sctx->client_cert_ctx)
    CertFreeCertificateContext(sctx->client_cert_ctx);
  if (crl_ctx)
    CertFreeCRLContext(crl_ctx);
  sctx->client_cert_ctx= NULL;
  return 1;
}