how to automaticaly export windows root certificates to a file? - certificate

On a windows machine, I want to create a c++ code that exports windows root certificates to .pem \ .crt file (just like certmgr.msc tool allows me to do manually).
currently digging in windows' cryptoAPI docs but didn't find something.
Edit:
after using the soltuion below the PEM certificates are created in the following format (unnecary newline between lines and an extra character at the end) : -----BEGIN CERTIFICATE-----
MIICvDCCAiUCEEoZ0jiMglkcpV1zXxVd3KMwDQYJKoZIhvcNAQEEBQAwgZ4xHzAd
BgNVBAoTFlZlcmlTaWduIFRydXN0IE5ldHdvcmsxFzAVBgNVBAsTDlZlcmlTaWdu
....
Rj1QNAufcFb2jip/F87lY795aQdzLrCVKIr17aqp0l3NCsoQCY/Os68olsR5KYSS
3P+6Z0JIppAQ5L9h+JxT5ZPRcz/4/Z1PhKxV0f0RY2M=
-----END CERTIFICATE-----
i don't believe it will be accepted by openSSL, what is the cause for this?

What you're looking for is CertEnumCertificatesInStore function.
Also if you want to save certificate in PEM you will need CryptBinaryToString.
#include <Windows.h>
#include <wincrypt.h>
#include <string>
#include <fstream>
#include <vector>
#pragma comment(lib, "crypt32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
DWORD num = 1;
/* open root certificate store */
HCERTSTORE hCertStore = CertOpenSystemStore(NULL, L"ROOT");
PCCERT_CONTEXT pCert = nullptr;
while (pCert = CertEnumCertificatesInStore(hCertStore, pCert))
{
/* if you need save certificate in PEM */
DWORD size = 0;
CryptBinaryToString(pCert->pbCertEncoded, pCert->cbCertEncoded, CRYPT_STRING_BASE64HEADER, nullptr, &size);
std::vector<wchar_t> pem(size);
CryptBinaryToString(pCert->pbCertEncoded, pCert->cbCertEncoded, CRYPT_STRING_BASE64HEADER,
pem.data(), &size);
std::wstring pem_cert = std::to_wstring(num) + L".pem";
std::wofstream pem_cert_file(pem_cert, std::ios::binary | std::ios::out);
pem_cert_file.write(pem.data(), pem.size() - 1);
/* or if you need save certificate in binary form (DER encoding)*/
std::string der_cert = std::to_string(num) + ".cer";
std::ofstream der_cert_file(der_cert, std::ios::binary | std::ios::out);
der_cert_file.write(reinterpret_cast<char*>(pCert->pbCertEncoded), pCert->cbCertEncoded);
++num;
}
CertCloseStore(hCertStore, 0);
return 0;
}

Related

Running WebServerSecure and PubSubClient on ESP8266

I wrote a sketch for ESP8266. This sketch reads some sensor data and published it via MQTT. In addition I want to let a Web server provide the same data as HTML, or JSON web service.
The MQTT publish is triggered via a TaskScheduler timer.
Both functions, MQTT and Web server, work for itself, but sadly not together. Here's a simplified sketch:
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServerSecure.h>
#include <PubSubClient.h>
#include <TaskScheduler.h>
#include <My_WLAN.h> // provices connection to local WLAN and network settings
const char DNS_NAME[] = "myserver.local";
const int HTTPS_PORT = 443; // HTTPS
const char MQTT_SVR[] = "myserver.local";
const unsigned int MQTT_PORT = 8883; // MQTTS
WiFiClientSecure wifiClient;
PubSubClient mqttClient(wifiClient); // MQTT client instance
ESP8266WebServerSecure server(HTTPS_PORT); // web server instance
void t1Callback(void); // callback method prototypes
Task t1(60000, TASK_FOREVER, &t1Callback); // main loop task
Scheduler timer; // task scheduler
static const uint8_t SVR_FINGERPRINT[20] PROGMEM = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20 };
static const char deviceCert[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
[... certificate ...]
-----END CERTIFICATE-----
)EOF";
static const char deviceKey[] PROGMEM = R"EOF(
-----BEGIN RSA PRIVATE KEY-----
[... key ...]
-----END RSA PRIVATE KEY-----
)EOF";
/* *****************************
MQTT_connect
* *****************************/
void MQTT_connect()
{
int attempt = 0;
/* loop until reconnected */
while (!mqttClient.connected() && attempt < 10) {
attempt++;
Serial.print("Attempting MQTT connection ("); Serial.print(attempt); Serial.print(")...");
mqttClient.setServer(MQTT_SVR, MQTT_PORT);
if (mqttClient.connect(DNS_NAME)) {
Serial.println("success");
} else {
Serial.print("failed, status code = "); Serial.print(mqttClient.state());
Serial.println(". - Try again in 5 seconds...");
delay(5000);
}
}
}
/* *****************************
Web Server handleRoot
* *****************************/
void handleRoot() {
digitalWrite(LED_BUILTIN, LOW); // on
Serial.println("WebServer ROOT");
server.send(200, "text/html", "WebServer ROOT");
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *****************************
Web Server handleNotFound
* *****************************/
void handleNotFound() {
digitalWrite(LED_BUILTIN, LOW); // on
String message = "File not found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *************************
MQTT_publish_something
* *************************/
void MQTT_publish_something() {
digitalWrite(LED_BUILTIN, LOW); // on
char payload[30] = "some_payload_data";
if (!mqttClient.publish("MQTT/Test", payload, true)) { // retain message
Serial.println("MQTT message lost!");
}
digitalWrite(LED_BUILTIN, HIGH); // off
}
/* *************************
t1: main timer (callback)
* *************************/
void t1Callback() {
my.WiFi_connect(); // check and re-connect to WLAN (in My_WLAN.h)
if (WiFi.status() == WL_CONNECTED) {
MQTT_connect();
MQTT_publish_something();
}
}
/* *************************
setup
* *************************/
void setup() {
pinMode(LED_BUILTIN, OUTPUT); // internal LED
digitalWrite(LED_BUILTIN, HIGH); // off
/* -----------------------
open Serial |
----------------------- */
Serial.begin(74880);
while (!Serial); // wait for Serial being ready
/* -----------------------
connect to WLAN |
----------------------- */
my.WiFi_connect(); // this is connecting to WLAN & error handling (in My_WLAN.h)
wifiClient.setFingerprint(SVR_FINGERPRINT);
/* -----------------------
set mDNS |
----------------------- */
if (MDNS.begin(DNS_NAME)) {
Serial.printf("mDNS responder started for %s\n", DNS_NAME);
MDNS.addService("https", "tcp", HTTPS_PORT); // add service to MDNS-SD
MDNS.addService("mqtt", "tcp", MQTT_PORT);
} else
Serial.println("Error setting up mDNS responder!");
/* -----------------------
start HTTPS server |
----------------------- */
server.getServer().setRSACert(new X509List(deviceCert), new PrivateKey(deviceKey));
server.on("/", handleRoot); // standard HTML root
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTPS server started.");
Serial.println();
/* -----------------------
start timer |
----------------------- */
timer.init();
timer.addTask(t1);
// line 177:
timer.enableAll();
}
void loop() {
MDNS.update();
// line 184:
server.handleClient();
mqttClient.loop();
timer.execute();
}
Running MQTT only works fine and publishes data (I use the mosquitto broker).
Running the Web server (https://...) works fine as well, if commenting out line 177 (so MQTT does not get triggered).
With both functions active, as soon as the first MQTT message had been sent, the web server does not answer any more. I get PR_END_OF_FILE_ERROR in FF and ERR_CONNECTION_CLOSED in Chrome.
I guess, that these libraries somehow mess with each other, or that something confuses with the certificates. However, the fingerprint belongs to the server running mosquitto, while the X509 certificate belongs to the web server running on the ESP8266. These are two different machines and have nothing to do with each other.
Any idea welcome.
I suspect both libraries use port 443, and you can only have one listener on a given port. I've tried creating a BearSSL::ESP8266WebServerSecure object with alternate ports, such as 80 and 8443 but can't get them to work. Worse, there doesn't seem to be a way to stop a listener once a BearSSL::ESP8266WebServerSecure object has started, so it can't be released for later reuse.
I ended up using HTTP to get WiFi credentials, then HTTPS from there on out. Not a very satisfactory solution but it works.
Update: I was able to run a provisioning server on port 443, stop it by calling
BearSSL::ESP8266WebServerSecure provisioningServer(443);
BearSSL::ESP8266WebServerSecure server(443);
provisioningServer.close();
provisioningServer.~ESP8266WebServerSecure(); // note: cannot use TLS on both servers without this line
After calling the provisioning server's destructor I was able to start my server on port 443.

Cannot do network programming in XCode anymore

Until recently, the following code worked perfectly in my project. But since a few days ago, it no longer works. I can replace the NSLog statements with printf statements, replace the other Obj-C style statements and compile with g++ in terminal it works just fine.
It should just connect to a very primitive server on a Raspberry Pi, send a single character 'R', and read back a 2-Byte integer. When I compiled or ran it in XCode months ago it worked. When I compile now in terminal with g++ it works. When I run in XCode now, though, it fails to open the socket and reports setDAC: connection failed.
I fear I may be going insane. Did Apple hide some new setting I need to turn on network access in XCode 9.4.1? Any advice?
Previously functional code in XCode:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include "stdio.h"
.
.
.
float readDAC(uint8_t ch){
if(!isConnected){
const char *servIP = [[txtIPAddress stringValue] UTF8String];
in_port_t servPort = 5001;
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock < 0){
NSLog(#"setDAC: Socket creation failed\n");
ok = false;
}
struct sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
int rtnVal = inet_pton(AF_INET, servIP, &servAddr.sin_addr.s_addr);
if(ok){
if(rtnVal == 0){
NSLog(#"setDAC: inet_pton() failed: invalid address string\n");
ok = false;
}
else if (rtnVal < 0){
NSLog(#"setDAC: inet_pton() failed\n");
ok = false;
}
servAddr.sin_port = htons(servPort);
}
if(ok) if(connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0){
NSLog(#"setDAC: connection failed\n");
ok = false;
}
datastream = fdopen(sock, "r+");
isConnected = true;
}
//send 'R' to read
//send 'W' to write
char writeChar = 'R';
if([AD5754 intValue]==1){
uint8_t writeChannel;
int16_t setVal;
float theVal;
uint8_t nDAC = 0;
if(ch>3) nDAC = 1;
ch = ch%4;
ch = 16*nDAC+ch;
writeChannel = ch;
fwrite(&writeChar, sizeof(writeChar), 1, datastream);
fwrite(&writeChannel, sizeof(writeChannel), 1, datastream);
fread(&setVal, sizeof(setVal), 1, datastream);
int16_t theSetVal;
theSetVal = ntohs(setVal);
theVal = (float)theSetVal/100;
NSLog(#"Read channel %i: %0.2f", ch, theVal);
fflush(datastream);
fclose(datastream);
return theVal;
}
I paid Apple the $99 annual fee to join the developer program and now the network coding works again. Not impressed with Apple, but ok.
I wouldn't mind paying to recover the functionality if it was documented or some notice was given. But I struggled for a few days before getting desperate enough to try throwing money at the problem, randomly.

aes_encrypt() function hooking

I want to know the pid of the process which is performing the AES encryption. I have written the following function hooking code:
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
#include <openssl/aes.h>
void AES_encrypt(const unsigned char *in_var, unsigned char *out_var,
const AES_KEY *key_var)
{
void (*new_aes_encrypt)(const unsigned char *in_var, unsigned char *out_var,
const AES_KEY *key_var);
new_aes_encrypt = dlsym(RTLD_NEXT, "AES_encrypt");
FILE *logfile = fopen("logfile", "a+");
fprintf(logfile, "Process %d:nn%snnn", getpid(), (char *)in_var);
fclose(logfile);
new_aes_encrypt(in_var, out_var, key_var);
}
Then at terminal I did the followings:
#gcc aes_hook.c -o aes_hook.so -fPIC -shared -lssl -D_GNU_SOURCE
#export LD_PRELOAD="/<directory location>/aes_hook.so"
However, when I started the AES encryption (by a dummy process), I could not get it's pid in logfile. Why is this hooking not working?
*P.S.: Following is the declaration of AES_encrypt (in aes.h of OpenSSL) function that is called to perform the AES encryption.
void AES_encrypt(const unsigned char *in, unsigned char *out,
const AES_KEY *key)

How to find Address already in use?

This is my code which can run CentOS and Windows just fixing some headers.
#define _WIN32_WINNT 0x0501
#include <WinSock2.h>
#include <WS2tcpip.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
/*
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
*/
int main()
{
int sock;
int ret = 0;
int port= 12345;
struct sockaddr_in addr;
char buf[1024];
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock<0){
printf("socket() ret = %d : %s\n",ret,strerror(errno));
return ret;
}
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if(ret<0){
printf("bind() ret = %d errno =%d : %s\n",ret,errno,strerror(errno));
return ret;
}
printf("############# Binding port %d type Enter to stop \t",port);
fgets(buf,sizeof(buf),stdin);
return 0;
}
When I tried to bind same port by this program with runing tow process, there must be the messages that Address already in use like below.
[The first proc#centOS ]
$ ./udp
############# Binding port 12345 type Enter to stop
[The second proc#centOS]
$ ./udp
bind() ret = -1 errno =98 : Address already in use
$
However when I do same thing with same code on windows, message is different.
[The first proc#windows]
C:\ >udp
############# Binding port 12345 type Enter to stop
[The second proc#windows]
C:\ >udp
bind() ret = -1 errno =34 : Result too large
C:\ >
How can I get Address already in use on Windows?
I don't think you should use errno on windows for sockets code. You could try to use WSAGetLastError which returns WSAEADDRINUSE.
The MSDN page for errno suggests EADDRINUSE is not supported for errno.
I think you should devise a scheme where you have a my_errno function that depending on the platform uses errno or WSAGetLastError.
printf("socket() ret = %d : %s\n",ret,strerror(errno));
There may be a subtle issue with this call. The order of argument evaluation is unspecified and strerror itself can change errno, which means it has side-effects. You should print errno separately, before doing anything else.
Like cnicular said, you have to use WSAGetLastError() on Windows, not errno. To get a text message for a socket error code, you can use FormatMessage().
To answer your question, if you want to find out who is using the port, you can use the command-line netstat tool, or programmably using GetTcpTable2().

g++ problem with -l option and PostgreSQL

I've written simple program.
Here a code:
#include <iostream>
#include <stdio.h>
#include <D:\Program Files\PostgreSQL\8.4\include\libpq-fe.h>
#include <string>
using namespace std;
int main()
{
PGconn *conn;
PGresult *res;
int rec_count;
int row;
int col;
cout << "ble ble: " << 8 << endl;
conn = PQconnectdb("dbname=db_pm host=localhost user=postgres password=postgres");
if (PQstatus(conn) == CONNECTION_BAD) {
puts("We were unable to connect to the database");
exit(0);
}
}
I'm trying to connect with PostgreSQL.
I compile this code with following command:
gcc -I/"d:\Program Files\PostgreSQL\" -L/"d:\Program Files\PostgreSQL\8.4\lib\" -lpq -o firstcpp.o firstcpp.cpp
This command is from following site:
http://www.mkyong.com/database/how-to-building-postgresql-libpq-programs/
And when I compile it I get following error:
/cygnus/cygwin-b20/H-i586-cygwin32/i586-cygwin32/bin/ld: cannot open -lpq: No such file or directory
collect2: ld returned 1 exit status
Does anyone help me?
Difek
You can try using forward slashes instead of backward slashes. And I have no idea about the first forward slash. Isn't it meant to be inside the quotes ? Eg -I"/d:/Program Files/PostgreSQL/"
Anyway, if you are using the gcc from cygwin, you could also try
-I"/cygdrive/d/Program Files/PostgreSQL"
And I'd do the same with that include (libpq-fe) - though apparently that is working, the error is in the linker.