I am trying to setup an example gSOAP server with SSL. I created a self signed certificate as this:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Then joined the certificates to one file:
cat cert.pem key.pem >both.pem
And then run this code:
#include <stdsoap2.h>
#include <stdexcept>
#include <sstream>
#include <iostream>
#define PORT 6667
int main(int argc, char **argv) {
struct soap engine(SOAP_C_UTFSTRING);
engine.bind_flags=SO_REUSEADDR;
soap_ssl_noinit();
int rc = soap_ssl_server_context(&engine,
SOAP_SSL_DEFAULT,
"both.pem", // keyfile
nullptr, // password
nullptr, // cacert
nullptr, // capath
nullptr, // dhfile
nullptr, // randfile
nullptr // serverid
);
if (rc) {
std::stringstream error;
soap_stream_fault(&engine, error);
throw std::runtime_error("soap_ssl_server context failed " + error.str());
}
rc = soap_bind(&engine, NULL, PORT, 100);
if (rc < 0) {
throw std::runtime_error("soap_bind failed " + std::to_string(rc));
}
int master_socket = rc;
std::cout << "master socket: " << master_socket << std::endl;
engine.accept_timeout = 50;
engine.send_timeout = 50;
engine.recv_timeout = 50;
rc = soap_ssl_accept(&engine);
if (rc) {
soap_stream_fault(&engine, std::cout);
throw std::runtime_error("soap_ssl_accept failed " + std::to_string(rc));
}
std::cout << "soap_ssl_accept " << rc << std::endl;
return 0;
}
But I get this output:
master socket: 3
Error 30 fault detected[no subcode]
"SSL/TLS error"
Detail: No socket in soap_ssl_accept()
terminate called after throwing an instance of 'std::runtime_error'
what(): soap_ssl_accept failed 30
What am I doing wrong?
I figured it out. One must call soap_accept before calling soap_ssl_accept. The correct code is:
rc = soap_accept(&engine);
if (rc) {
soap_stream_fault(&engine, std::cout);
throw std::runtime_error("soap_accept failed " + std::to_string(rc));
}
rc = soap_ssl_accept(&engine);
if (rc) {
soap_stream_fault(&engine, std::cout);
throw std::runtime_error("soap_ssl_accept failed " + std::to_string(rc));
}
and then the error is fixed.
Related
This code block works perfectly well if I use port 22 to connect in ssh (rather usual 22 basic port of ssh)
But for some reason, I need to connect to ssh on port 443. And at this moment the code doesn't work anymore and tries to connect always on port 22.
So I ask if there is a method to tell the libgit2 to use port 443 for ssh connection.
int creds(git_cred **out, const char *url, const char *username_from_url,
unsigned int allowed_types, void *payload) {
std::cout << "Calling creds" << std::endl;
int result = git_credential_ssh_key_new(out, username_from_url,"path/to/ssh_key_public", "path/to/ssh_key_private", "");
if (result != 0) {
std::cout << giterr_last()->message << std::endl;
throw;
return result;
}
return result;
}
int main() {
git_libgit2_init();
git_repository *repo = nullptr;
git_remote *local_remote = nullptr;
std::string repo_path = "/Users/luclambour/Desktop/repo_test_libgit/git-test-clone";
int error = 0;
error = git_repository_open(&repo, repo_path.data());
std::cout<<error<<std::endl;
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
error =git_remote_create_anonymous(&local_remote, repo, "root#138.1.1.1:/root/luc_clone_des/clone_simple");
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
callbacks.credentials=creds;
error = git_remote_connect(local_remote, GIT_DIRECTION_PUSH, &callbacks, NULL, NULL);
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_push_options opts = GIT_PUSH_OPTIONS_INIT;
opts.callbacks.credentials = creds;
opts.proxy_opts.type = GIT_PROXY_NONE;
error = git_remote_push(local_remote,NULL,&opts);
if (error != 0) { std::cout << giterr_last()->message << std::endl;}
git_remote_free(local_remote);
git_repository_free(repo);
git_libgit2_shutdown();
return 0;
}
scp-like syntax doesn't support port number, so you should use ssh:// URL syntax as:
git_remote_create_anonymous(&local_remote, repo, "ssh://root#138.1.1.1:443/root/luc_clone_des/clone_simple");
Details can be found in the "GIT URLS" section of git-clone(1).
https://git-scm.com/docs/git-clone#_git_urls
I have some generated SPIR-V code which I want to use with the vulkan API. But I get an
Exception thrown at 0x00007FFB68D933CB (nvoglv64.dll) in vulkanCompute.exe: 0xC0000005: Access violation reading location 0x0000000000000008. when trying to create the pipline with vkCreateComputePipelines.
The API calls should be fine, because the same code works with a shader compiled with glslangValidator. Therefore I assume that the generated SPIR-V code must be illformed somehow.
I've checked the SPIR-V code with the validator tool from khronos, using spirv-val --target-env vulkan1.1 mainV.spv which exited without error. Anyhow it is also known that this tool is still incomplete.
I've also tried to use the Radeon GPU Analyzer to compile my SPIR-V code, which is also available online at the shader playground and this tool throws the error Error: Error: internal error: Bil::BilInstructionConvert::Create(60) Code Not Tested! which is not really helpful, but encourages the assumption that the code is malformed.
The SPIR-V code is unfortunately to long to post it here, but it is in the link of the shader playground.
Does anyone know what the problem is with my setting or has any idea how I can verify my SPIR-V code in a better way, without checking all 700 lines of code manually.
I don't thinkt the problem is there, but anyway here is the c++ host code:
#include "vulkan/vulkan.hpp"
#include <iostream>
#include <fstream>
#include <vector>
#define BAIL_ON_BAD_RESULT(result) \
if (VK_SUCCESS != (result)) \
{ \
fprintf(stderr, "Failure at %u %s\n", __LINE__, __FILE__); \
exit(-1); \
}
VkResult vkGetBestComputeQueueNPH(vk::PhysicalDevice &physicalDevice, uint32_t &queueFamilyIndex)
{
auto properties = physicalDevice.getQueueFamilyProperties();
int i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (!(vk::QueueFlagBits::eGraphics & maskedFlags) && (vk::QueueFlagBits::eCompute & maskedFlags))
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
i = 0;
for (auto prop : properties)
{
vk::QueueFlags maskedFlags = (~(vk::QueueFlagBits::eTransfer | vk::QueueFlagBits::eSparseBinding) & prop.queueFlags);
if (vk::QueueFlagBits::eCompute & maskedFlags)
{
queueFamilyIndex = i;
return VK_SUCCESS;
}
i++;
}
return VK_ERROR_INITIALIZATION_FAILED;
}
int main(int argc, const char *const argv[])
{
(void)argc;
(void)argv;
try
{
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo("VecAdd", 1, "Vulkan.hpp", 1, VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
std::vector<char *> layers = {
"VK_LAYER_LUNARG_api_dump",
"VK_LAYER_KHRONOS_validation"
};
vk::InstanceCreateInfo instanceCreateInfo({}, &applicationInfo, static_cast<uint32_t>(layers.size()), layers.data());
// create a UniqueInstance
vk::UniqueInstance instance = vk::createInstanceUnique(instanceCreateInfo);
auto physicalDevices = instance->enumeratePhysicalDevices();
for (auto &physicalDevice : physicalDevices)
{
auto props = physicalDevice.getProperties();
// get the QueueFamilyProperties of the first PhysicalDevice
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
uint32_t computeQueueFamilyIndex = 0;
// get the best index into queueFamiliyProperties which supports compute and stuff
BAIL_ON_BAD_RESULT(vkGetBestComputeQueueNPH(physicalDevice, computeQueueFamilyIndex));
std::vector<char *>extensions = {"VK_EXT_external_memory_host", "VK_KHR_shader_float16_int8"};
// create a UniqueDevice
float queuePriority = 0.0f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), static_cast<uint32_t>(computeQueueFamilyIndex), 1, &queuePriority);
vk::StructureChain<vk::DeviceCreateInfo, vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceShaderFloat16Int8Features> createDeviceInfo = {
vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, 0, nullptr, static_cast<uint32_t>(extensions.size()), extensions.data()),
vk::PhysicalDeviceFeatures2(),
vk::PhysicalDeviceShaderFloat16Int8Features()
};
createDeviceInfo.get<vk::PhysicalDeviceFeatures2>().features.setShaderInt64(true);
createDeviceInfo.get<vk::PhysicalDeviceShaderFloat16Int8Features>().setShaderInt8(true);
vk::UniqueDevice device = physicalDevice.createDeviceUnique(createDeviceInfo.get<vk::DeviceCreateInfo>());
auto memoryProperties2 = physicalDevice.getMemoryProperties2();
vk::PhysicalDeviceMemoryProperties const &memoryProperties = memoryProperties2.memoryProperties;
const int32_t bufferLength = 16384;
const uint32_t bufferSize = sizeof(int32_t) * bufferLength;
// we are going to need two buffers from this one memory
const vk::DeviceSize memorySize = bufferSize * 3;
// set memoryTypeIndex to an invalid entry in the properties.memoryTypes array
uint32_t memoryTypeIndex = VK_MAX_MEMORY_TYPES;
for (uint32_t k = 0; k < memoryProperties.memoryTypeCount; k++)
{
if ((vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent) & memoryProperties.memoryTypes[k].propertyFlags &&
(memorySize < memoryProperties.memoryHeaps[memoryProperties.memoryTypes[k].heapIndex].size))
{
memoryTypeIndex = k;
std::cout << "found memory " << memoryTypeIndex + 1 << " out of " << memoryProperties.memoryTypeCount << std::endl;
break;
}
}
BAIL_ON_BAD_RESULT(memoryTypeIndex == VK_MAX_MEMORY_TYPES ? VK_ERROR_OUT_OF_HOST_MEMORY : VK_SUCCESS);
auto memory = device->allocateMemoryUnique(vk::MemoryAllocateInfo(memorySize, memoryTypeIndex));
auto in_buffer = device->createBufferUnique(vk::BufferCreateInfo(vk::BufferCreateFlags(), bufferSize, vk::BufferUsageFlagBits::eStorageBuffer, vk::SharingMode::eExclusive));
device->bindBufferMemory(in_buffer.get(), memory.get(), 0);
// create a DescriptorSetLayout
std::vector<vk::DescriptorSetLayoutBinding> descriptorSetLayoutBinding{
{0, vk::DescriptorType::eStorageBuffer, 1, vk::ShaderStageFlagBits::eCompute}};
vk::UniqueDescriptorSetLayout descriptorSetLayout = device->createDescriptorSetLayoutUnique(vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), static_cast<uint32_t>(descriptorSetLayoutBinding.size()), descriptorSetLayoutBinding.data()));
std::cout << "Memory bound" << std::endl;
std::ifstream myfile;
myfile.open("shaders/MainV.spv", std::ios::ate | std::ios::binary);
if (!myfile.is_open())
{
std::cout << "File not found" << std::endl;
return EXIT_FAILURE;
}
auto size = myfile.tellg();
std::vector<unsigned int> shader_spv(size / sizeof(unsigned int));
myfile.seekg(0);
myfile.read(reinterpret_cast<char *>(shader_spv.data()), size);
myfile.close();
std::cout << "Shader size: " << shader_spv.size() << std::endl;
auto shaderModule = device->createShaderModuleUnique(vk::ShaderModuleCreateInfo(vk::ShaderModuleCreateFlags(), shader_spv.size() * sizeof(unsigned int), shader_spv.data()));
// create a PipelineLayout using that DescriptorSetLayout
vk::UniquePipelineLayout pipelineLayout = device->createPipelineLayoutUnique(vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), 1, &descriptorSetLayout.get()));
vk::ComputePipelineCreateInfo computePipelineInfo(
vk::PipelineCreateFlags(),
vk::PipelineShaderStageCreateInfo(
vk::PipelineShaderStageCreateFlags(),
vk::ShaderStageFlagBits::eCompute,
shaderModule.get(),
"_ZTSZZ4mainENK3$_0clERN2cl4sycl7handlerEE6VecAdd"),
pipelineLayout.get());
auto pipeline = device->createComputePipelineUnique(nullptr, computePipelineInfo);
auto descriptorPoolSize = vk::DescriptorPoolSize(vk::DescriptorType::eStorageBuffer, 2);
auto descriptorPool = device->createDescriptorPool(vk::DescriptorPoolCreateInfo(vk::DescriptorPoolCreateFlags(), 1, 1, &descriptorPoolSize));
auto commandPool = device->createCommandPoolUnique(vk::CommandPoolCreateInfo(vk::CommandPoolCreateFlags(), computeQueueFamilyIndex));
auto commandBuffer = std::move(device->allocateCommandBuffersUnique(vk::CommandBufferAllocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1)).front());
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlags(vk::CommandBufferUsageFlagBits::eOneTimeSubmit)));
commandBuffer->bindPipeline(vk::PipelineBindPoint::eCompute, pipeline.get());
commandBuffer->dispatch(bufferSize / sizeof(int32_t), 1, 1);
commandBuffer->end();
auto queue = device->getQueue(computeQueueFamilyIndex, 0);
vk::SubmitInfo submitInfo(0, nullptr, nullptr, 1, &commandBuffer.get(), 0, nullptr);
queue.submit(1, &submitInfo, vk::Fence());
queue.waitIdle();
printf("all done\nWoohooo!!!\n\n");
}
}
catch (vk::SystemError &err)
{
std::cout << "vk::SystemError: " << err.what() << std::endl;
exit(-1);
}
catch (std::runtime_error &err)
{
std::cout << "std::runtime_error: " << err.what() << std::endl;
exit(-1);
}
catch (...)
{
std::cout << "unknown error\n";
exit(-1);
}
return EXIT_SUCCESS;
}
Well after checking out line per line it showed that the problem is when working with pointers of pointers. For me it is still not clear from the specification that it is not allowed, but it is understandable that it does not work with logical pointers.
Still the behaviour is strange that the validator is not able to note that and that compiling the SPIRV code crashes instead of throwing a clear error message.
So in the end, it was the Shader code which was wrong.
I want to create an SSL connection with my site to send data and every time I connect it fails!
I am using WiFiClientSecure.h library but I don't know where is the problem is it from code or library or from my site?
here is my code:
#include <ArduinoJson.h>
#include <ESP8266WiFi.h>
#include <DHT.h>
#include <WiFiClientSecure.h>
#define DHTPIN D6
#define DHTTYPE DHT11
const char* ssid = "SSID";
const char* password = pass";
char host[] = "mysite.com";
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
delay(100);
dht.begin();
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
Serial.print("Netmask: ");
Serial.println(WiFi.subnetMask());
Serial.print("Gateway: ");
Serial.println(WiFi.gatewayIP());
}
void loop (){
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return;
}
Serial.print("connecting to ");
Serial.println(host);
int httpPort = 443;
//Add a SSL client
WiFiClientSecure client;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
String url = "/insert.php?temp=" + String(t) + " ;
Serial.print("Requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(500);
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("closing connection");
}
Is the issue in the code or from my site?
The ESP8266 is an embedded processor. It has many limitations. One of them is that it doesn't store certificates for any CAs.
As the documentation for the esp32 says "here are three ways to establish a secure connection using the WiFiClientSecure class: using a root certificate authority (CA) cert, using a root CA cert plus a client cert and key, and using a pre-shared key (PSK)."
If your cert is signed by a server with a well known CA then you can use CA method. You call the setCACert function with the certifcate that you can obtain using openssl. You need to save this certificate in as an array. It should look someling like this (DER) format.
const char* test_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/\n" \
"MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT\n" \
"DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow\n" \
"SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT\n" \
............
"KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==\n" \
"-----END CERTIFICATE-----\n";
The in your code you should place a
client.setCACert(test_root_ca);
before you call the client.connect.
i'm doing a code for server client the server is CA and the client sends signed request to server and the server create signed certificate then the client sends to the server its certificate. The server first verify the certificate. also the client Extract the serial number of the certificate
i have some problems here
1- the verify process fail
verifiy fail
certificate signature failure
2- the serial number is always return a constant number 3 i don't know why
thx allot for helping me
certificate.cpp
#include <iostream>
#include "server.h"
#include "client.h"
using namespace std;
int main()
{
Client clientest;
Server servertest;
X509 *cert;
cert = servertest.CreateCertificate(clientest.MakeSignedCertReq());
clientest.SetCert(cert);
clientest.CertConverter();
X509 *test;
test = clientest.GetCert();
servertest.CheckCert(cert);
int serial = 0;
serial = clientest.ExtractCertSerial();
cout<<"client serial is "<<serial<<endl;
return 0;
}
server.h
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include <openssl/asn1.h>
#include <openssl/ssl.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include "client.h"
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
using namespace std;
class Server
{
public:
Server();
~Server();
X509 *CreateCertificate (X509_REQ *req);
void CreateMyCertificate();
void GenerateMyKeyPairs ( );
void SetPublicKey ();
int CheckCert (X509 *clientcert);
private:
X509 *m_myCert;
RSA *m_caKeyPairs;
EVP_PKEY *m_pukey;
X509_NAME *m_issuerName;
};
#endif /* SERVER_H_ */
server.cc
#include "server.h"
Server::Server()
{
m_myCert = X509_new();
m_caKeyPairs = RSA_new();
m_pukey = EVP_PKEY_new();
m_issuerName = X509_NAME_new();
GenerateMyKeyPairs();
CreateMyCertificate();
//SetPublicKey();
}
Server::~Server()
{
X509_free(m_myCert);
RSA_free(m_caKeyPairs);
X509_NAME_free(m_issuerName);
}
X509*
Server::CreateCertificate(X509_REQ* req)
{
cout<<"hello i began"<<endl;
X509 *m_req_reply;
m_req_reply = X509_new();
X509_NAME *subject = NULL;
EVP_PKEY *pkey = NULL;
ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2);
X509_gmtime_adj(X509_get_notBefore(m_req_reply), 0);
X509_gmtime_adj(X509_get_notAfter(m_req_reply), 31536000L);
pkey = X509_REQ_get_pubkey(req);
X509_set_pubkey(m_req_reply, pkey);
X509_NAME *issuerSubject = X509_get_subject_name(m_myCert);
X509_set_issuer_name(m_req_reply, issuerSubject);
//extract the subject of the request
subject = X509_REQ_get_subject_name(req);
X509_set_subject_name(m_req_reply, subject);
cout << "cert subject name:" << X509_get_subject_name(m_req_reply) << endl;
if(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1()))
cout << "client cert ok\n";
else
cout << "client cert error\n";
return m_req_reply;
}
void
Server::CreateMyCertificate()
{
// we use rsa pairs and assign it into evp_key
SetPublicKey();
// properties of the certificate
//set the serial number
ASN1_INTEGER_set(X509_get_serialNumber(m_myCert), 1);
//set the time validity
X509_gmtime_adj(X509_get_notBefore(m_myCert), 0);
X509_gmtime_adj(X509_get_notAfter(m_myCert), 31536000L);
//set the public key of the cert to be signed
X509_set_pubkey(m_myCert, m_pukey);
//this is a self-signed certificate, we set the name of the issuer to the name of the subject
m_issuerName = X509_get_subject_name(m_myCert);
X509_NAME_add_entry_by_txt(m_issuerName, "C", MBSTRING_ASC,
(unsigned char *)"CA", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "O", MBSTRING_ASC,
(unsigned char *)"MyCompany Inc.", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_issuerName, "CN", MBSTRING_ASC,
(unsigned char *)"localhost", -1, -1, 0);
//set the issuer name
X509_set_issuer_name(m_myCert, m_issuerName);
//sign the cert
if(1 == X509_sign(m_myCert, m_pukey, EVP_sha1()))
cout << "self cert signed ok\n";
else
cout << "self cert sign error\n";
FILE * fcert;
fcert = fopen("cert.pem", "wb");
PEM_write_X509(
fcert, /* write the certificate to the file we've opened */
m_myCert /* our certificate */
);
}
void
Server::GenerateMyKeyPairs()
{
m_caKeyPairs = RSA_generate_key(2048,RSA_F4 , NULL , NULL);
}
void
Server::SetPublicKey()
{
if(1 == EVP_PKEY_assign_RSA(m_pukey,m_caKeyPairs))
cout << "key assigned OK\n";
else
cout << "key assign error\n";
BIO *out = NULL;
const char szPath[10] = "key2.pem";
out = BIO_new_file(szPath,"wb");
EVP_PKEY_print_private(out, m_pukey,
0, NULL);
BIO_free(out);
out = BIO_new_file("key.pem","wb");
//print the self signed certificate
//FILE * fkey;
//fkey = fopen("key.pem", "wb");
PEM_write_bio_PrivateKey(
out, /* write the key to the file we've opened */
m_pukey, /* our key from earlier */
EVP_des_ede3_cbc(), /* default cipher for encrypting the key on disk */
(unsigned char *)"replace_me", /* passphrase required for decrypting the key on disk */
10, /* length of the passphrase string */
NULL, /* callback for requesting a password */
NULL /* data to pass to the callback */
);
}
int
Server::CheckCert(X509* clientcert)
{
int status = 0;
X509_STORE_CTX *ctx = X509_STORE_CTX_new();
//void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx);
//void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
//store the trusted cert into ctx
X509_STORE *store = X509_STORE_new();
X509_STORE_add_cert(store, m_myCert);
//put the trusted cert and cert then verify it
X509_STORE_CTX_init(ctx,store, clientcert, NULL);
status = X509_verify_cert(ctx);
//status = X509_verify(clientcert, m_pukey);
if (status == 1)
{
cout<<"verified succesfully"<<endl;
}
else
{
cout<<"verifiy fail"<<endl;
cout << X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx));
}
return status;
}
client.h
#ifndef CLIENT_H_
#define CLIENT_H_
#include <stdlib.h>
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/conf.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include "server.h"
class Client
{
public:
Client();
~Client();
void GenerateRSAKeyPair ();
void SetPublicKey ();
X509_REQ *MakeSignedCertReq();
void SetCert (X509 *cert);
X509 *GetCert();
int CertConverter ();
int ExtractCertSerial ();
private:
X509_REQ *m_myCertReq;
X509 *m_myCert;
X509_NAME *m_name;
RSA *m_rsa_keyPair;
EVP_PKEY *m_puk;
};
#endif /* CLIENT_H_ */
client.cc
#include "client.h"
Client :: Client()
{
m_myCertReq = X509_REQ_new();
m_myCert = X509_new();
m_name = X509_NAME_new();
m_rsa_keyPair = RSA_new();
m_puk = EVP_PKEY_new();
GenerateRSAKeyPair();
// SetPublicKey();
}
Client :: ~Client()
{
X509_REQ_free(m_myCertReq);
X509_free(m_myCert);
//X509_NAME_free(m_name);
RSA_free(m_rsa_keyPair);
//EVP_PKEY_free(m_puk);
}
void
Client :: GenerateRSAKeyPair ( )
{
m_rsa_keyPair = RSA_generate_key(2048,RSA_F4,NULL,NULL);
BIO *pubout = NULL;
const char szPath[10] = "clrsa.pem";
pubout = BIO_new_file(szPath,"wb");
PEM_write_bio_RSAPublicKey (pubout , m_rsa_keyPair);
}
void
Client::SetPublicKey()
{
EVP_PKEY_assign_RSA(m_puk,m_rsa_keyPair);
BIO *out = NULL;
const char szPath[10] = "cpuky.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_PUBKEY(out,m_puk);
}
X509_REQ*
Client::MakeSignedCertReq()
{
SetPublicKey();
//include the public key in the req
X509_REQ_set_pubkey(m_myCertReq,m_puk);
//set the subject name of the request
m_name=X509_REQ_get_subject_name(m_myCertReq);
//set the request
X509_NAME_add_entry_by_txt(m_name,"C",MBSTRING_ASC, (const unsigned char *)"UK", -1, -1, 0);
X509_NAME_add_entry_by_txt(m_name,"CN",MBSTRING_ASC, (const unsigned char *)"OpenSSL Group", -1, -1, 0);
//sign the req
X509_REQ_sign(m_myCertReq,m_puk,EVP_sha1());
BIO *out = NULL;
const char szPath[10] = "req.pem";
out = BIO_new_file(szPath,"wb");
PEM_write_bio_X509_REQ(out,m_myCertReq);
return m_myCertReq;
}
void
Client::SetCert(X509 *cert)
{
cout << "writing certificate\n";
BIO *out = NULL;
const char szPath[10] = "x509.pem";
out = BIO_new_file(szPath,"wb");
m_myCert = cert;
int len;
unsigned char *buf, *p;
len = i2d_X509(cert, NULL);
cout << "cert length =" << len << endl;
buf = (unsigned char *)OPENSSL_malloc(len);
p = buf;
i2d_X509(cert, &p);
cout << "cert= "<<endl;
for(int i=0; i<len; i++)
cout << buf[i];
cout << endl;
if(!PEM_write_bio_X509 (out , cert))
cout << "error writing certificate\n";
}
int
Client::CertConverter()
{
int len = i2d_X509(m_myCert, NULL);
unsigned char *buf, *p;
buf = (unsigned char *)OPENSSL_malloc(len);
p = buf;
i2d_X509(m_myCert, &p);
unsigned char certarray[len];
for (int i = 0 ; i<len ; i++)
{
certarray[i] = *(p-len+i);
}
cout << "converted client cert is"<<endl;
for (int j = 0 ; j<len ; j++)
{
cout << certarray[j];
}
cout<<endl;
/*
X509 *certtest = NULL;
certtest = d2i_X509(NULL, certarray , len);
cout<<"write the array to file"<<endl;
FILE * fcert;
fcert = fopen("certarray.pem", "wb");
PEM_write_X509(
fcert, //write the certificate to the file we've opened
certtest //our certificate
);
*/
return 0;
}
X509*
Client::GetCert()
{
return m_myCert;
}
int
Client::ExtractCertSerial()
{
int serial = 0;
unsigned char **out = NULL;
ASN1_INTEGER *asn1_serial = NULL;
asn1_serial = X509_get_serialNumber(m_myCert);
serial = i2d_ASN1_INTEGER(asn1_serial, out);
return (serial);
}
hope that any one can help me soon to solve my problem
note i have the self signed cert created well in cert.pem file also the x509.pem (for the client ) is created well but when i verify it i got an error all the time not verified because of the certificate signature failure when i got error handler X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)) also the serial number is always constant 3
I found out that in the request should add
//adds all digest algorithms to the table
OpenSSL_add_all_digests();
without this line the certificate will never be verified correctly
In CreateCertificate(X509_REQ* req){...}, you have
ASN1_INTEGER_set(X509_get_serialNumber(m_req_reply), 2); so you
will always set the serial number to 2(3).
Also in CreateCertificate(X509_REQ* req){...}, you haveif(1 == X509_sign(m_req_reply, m_pukey, EVP_sha1())) but X509_sign(...) will return the size of the signature instead of 1 if it succeeds.
Here's my simple openssl client test case trying to connect to google.com:443.
According to the manual, BIO_do_connect should return 1, 0 or -1.
Google didn't find me anyone for whom it returns 0, which it does for me.
#include <stdio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
int main()
{
SSL_load_error_strings();
SSL_library_init();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX *p_ssl_ctx = NULL;
SSL *p_ssl = NULL;
BIO * bio = NULL;
int r = 0;
// init ssl context
p_ssl_ctx = SSL_CTX_new(SSLv2_client_method()); /* Create new context */
if (p_ssl_ctx == NULL)
{
ERR_print_errors_fp(stderr);
return 3;
}
const char *store_path = "/etc/ssl/certs/ca-certificates.crt";
r = SSL_CTX_load_verify_locations(p_ssl_ctx, store_path, NULL);
if (r == 0) {
fprintf(stderr, "Unable to load the trust store from %s.\n", store_path);
return 4;
}
bio = BIO_new_ssl_connect(p_ssl_ctx);
if (!bio) {
fprintf(stderr, "no bio \n");
return 5;
}
BIO_get_ssl(bio, &p_ssl);
if (!(p_ssl)) {
fprintf(stderr, "no ssl\n");
return 6;
}
SSL_set_mode(p_ssl, SSL_MODE_AUTO_RETRY);
BIO_set_conn_hostname(bio, "www.google.com:443");
r = BIO_do_connect(bio);
if (r < 1) {
fprintf(stderr, "BIO_new_ssl_connect failed: %lu (0x%lx)\n", r, r);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
fprintf(stderr, "%s\n", ERR_error_string(ERR_get_error(), NULL));
ERR_print_errors_fp(stderr);
perror("bio");
return 7;
}
if (SSL_get_verify_result(p_ssl) != X509_V_OK) {
fprintf(stderr, "Unable to verify connection result.\n");
return 8;
}
return 0;
}
returns:
BIO_new_ssl_connect failed: 0 (0x0)
Error: (null)
error:00000000:lib(0):func(0):reason(0)
bio: Success
so how do i get the actual error out of this?
For getting the last state of your SSL connection in your code you can add something like fprintf(stderr,"p_ssl state: %s\n",SSL_state_string_long(p_ssl));.
More generally I suggest you to add an info callback like this : http://www.openssl.org/docs/ssl/SSL_CTX_set_info_callback.html
For your case, you must replace SSLv2_client_method() by something like TLSv1_client_method().