Skip to content

Commit

Permalink
Add X509 encoding test
Browse files Browse the repository at this point in the history
  • Loading branch information
Jean-Romain Garnier committed Jan 26, 2023
1 parent a01c196 commit a3c3628
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 0 deletions.
7 changes: 7 additions & 0 deletions proto/asn1-pdu/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
*.py
*.pyc
__pycache__

*.pb.h
*.pb.cc
*.o
14 changes: 14 additions & 0 deletions proto/asn1-pdu/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
LPM_DIR=../../../libprotobuf-mutator
PROTOBUF_DIR=$(LPM_DIR)/build/external.protobuf
FLAGS=-O2 -Wall -Wextra -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fstack-clash-protection -fPIE -fPIC -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code

all: proto cpp

proto: *.proto
protoc *.proto --python_out=. --cpp_out=.

cpp: *.h *.cc
$(CXX) -c $(FLAGS) *.cc -I$(LPM_DIR) -I$(PROTOBUF_DIR)/include

clean:
$(RM) *.o
5 changes: 5 additions & 0 deletions proto/tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.py
*.pyc
*.pem
*.der
*.proto
16 changes: 16 additions & 0 deletions proto/tests/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
LPM_DIR=../../../libprotobuf-mutator
PROTOBUF_DIR=$(LPM_DIR)/build/external.protobuf
ASN1_PROTOBUF_DIR=../asn1-pdu
FLAGS=-O2 -Wall -Wextra -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fstack-clash-protection -fPIE -fPIC -Wl,-z,relro -Wl,-z,now -Wl,-z,noexecstack -Wl,-z,separate-code

all: protobuf tests

protobuf:
$(MAKE) -C $(ASN1_PROTOBUF_DIR) all

tests: protobuf_to_der.cpp
$(CXX) $(FLAGS) -o protobuf_to_der.o protobuf_to_der.cpp $(ASN1_PROTOBUF_DIR)/*.o -I$(PROTOBUF_DIR)/include -I$(LPM_DIR) -I$(ASN1_PROTOBUF_DIR) $(LPM_DIR)/build/src/libfuzzer/libprotobuf-mutator-libfuzzer.a $(LPM_DIR)/build/src/libprotobuf-mutator.a $(PROTOBUF_DIR)/lib/libprotobuf.a -lcrypto

clean:
$(RM) *.o
$(MAKE) -C $(ASN1_PROTOBUF_DIR) clean
56 changes: 56 additions & 0 deletions proto/tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Proto tests

## Setup

Clone and build `libprotobuf-mutator`:

```sh
$ git clone https://github.com/google/libprotobuf-mutator.git libprotobuf-mutator
$ cd libprotobuf-mutator
$ mkdir build && cd build
$ cmake .. -GNinja -DLIB_PROTO_MUTATOR_DOWNLOAD_PROTOBUF=ON -DLIB_PROTO_MUTATOR_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
$ ninja
```

Clone `google-fuzzing` and build test files:

```
$ git clone https://github.com/google/fuzzing.git fuzzing
$ cd fuzzing/proto/tests
$ make
```

## Run

Generate python files:

```sh
$ protoc ../asn1-pdu/*.proto --python_out=../asn1-pdu
```

Generate a test certificate and convert it to the DER format:

```sh
$ openssl req -nodes -new -x509 -keyout key.pem -out cert.pem
$ openssl x509 -in cert.pem -out cert.der -outform DER
```

Convert it to protobuf:

```sh
$ ./x509_to_protobuf.py cert.pem cert.proto
```

Convert the protobuf back to DER:

```sh
$ ./protobuf_to_der.o cert.proto cert-2.der
```

Make sure OpenSSL can properly parse the certificate and compare it to the
initial one:

```
$ openssl x509 -inform DER -in cert-2.der -noout -text
$ openssl x509 -inform DER -in cert.der -noout -text
```
62 changes: 62 additions & 0 deletions proto/tests/protobuf_to_der.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#include <fstream>
#include <openssl/evp.h>
#include "x509_certificate.pb.h"

#include "asn1_pdu_to_der.h"
#include "x509_certificate_to_der.h"

std::string base64_encode(const unsigned char *buf, int len) {
const auto expected_size = 4 * ((len + 2) / 3);
auto output = reinterpret_cast<char *>(calloc(expected_size + 1, 1));
const auto actual_size = EVP_EncodeBlock(reinterpret_cast<unsigned char *>(output), buf, len);
if (expected_size != actual_size) {
std::cerr << "Wrong base64 output length: expected " << expected_size << " but got " << actual_size << ".\n";
}
return output;
}

std::string readFile(const char* path) {
printf("Reading file at %s\n", path);
std::ifstream file(path, std::ios::in | std::ios::binary);
std::string str = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
printf("Read %ld bytes\n\n", str.length());
return str;
}

void writeFile(const char* path, std::vector<uint8_t> data) {
printf("Writing %ld bytes to %s\n", data.size(), path);
std::ofstream file(path, std::ios::out | std::ios::binary);
std::copy(data.begin(), data.end(), std::ostreambuf_iterator<char>(file));
}

int main(int argc, char **argv) {
if (argc != 3) {
printf("Usage: ./protobuf_to_der.o <in file> <out file>\n");
return 1;
}

std::string protobuf = readFile(argv[1]);
std::string b64Protobuf = base64_encode((unsigned char *)protobuf.c_str(), protobuf.length());
printf("Protobuf: %s\n\n", b64Protobuf.c_str());

x509_certificate::X509Certificate input;
bool parse_ok = input.ParseFromArray(protobuf.c_str(), protobuf.length());
if (!parse_ok) {
printf("ParseFromArray failed!\n");
return 1;
}

std::string serialized;
input.SerializeToString(&serialized);
std::string b64Serialized = base64_encode((unsigned char *)serialized.c_str(), serialized.length());
printf("Re-serialized protobuf: %s\n\n", b64Serialized.c_str());

std::vector<uint8_t> asn1 = x509_certificate::X509CertificateToDER(input);

std::string b64asn1 = base64_encode(asn1.data(), asn1.size());
printf("ASN.1: %s\n", b64asn1.c_str());

writeFile(argv[2], asn1);

return 0;
}
Binary file added proto/tests/protobuf_to_der.o
Binary file not shown.
2 changes: 2 additions & 0 deletions proto/tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
asn1crypto
protobuf

0 comments on commit a3c3628

Please sign in to comment.