Skip to content

Commit

Permalink
Remove doublicate code when decompressing a certificate
Browse files Browse the repository at this point in the history
  • Loading branch information
aveenismail committed Nov 10, 2023
1 parent c0344a3 commit daf69b1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 92 deletions.
73 changes: 33 additions & 40 deletions lib/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,8 @@
*
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <ctype.h>
#include <time.h>

#include <zlib.h>
Expand Down Expand Up @@ -1388,52 +1385,60 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) {
return (uint32_t)object_id;
}

ykpiv_rc ykpiv_util_decompressed_cert(uint8_t *buf, size_t len, uint8_t *buf_ptr,
unsigned char *decompressed_data, unsigned long *decompressed_data_len) {
ykpiv_rc ykpiv_util_get_certdata(uint8_t *buf, size_t buf_len, uint8_t* certdata, unsigned long *certdata_len) {
size_t offs, len = 0;
uint8_t *ptr = buf;
unsigned long ul_buflen = (unsigned long)buf_len;

if (buf[len - 3]) { // This byte is set to 1 if certinfo is YKPIV_CERTINFO_GZIP
ptr++;
offs = _ykpiv_get_length(ptr, buf + ul_buflen, &len);
if(!offs) {
*certdata_len = 0;
return YKPIV_OK;
}
ptr += offs;

if (buf[buf_len - 3]) { // This byte is set to 1 if certinfo is YKPIV_CERTINFO_GZIP
z_stream zs;
zs.zalloc = Z_NULL;
zs.zfree = Z_NULL;
zs.opaque = Z_NULL;
zs.avail_in = (uInt) len;
zs.next_in = (Bytef *) buf_ptr;
zs.avail_out = (uInt) *decompressed_data_len;
zs.next_out = (Bytef *) decompressed_data;
zs.next_in = (Bytef *) ptr;
zs.avail_out = (uInt) *certdata_len;
zs.next_out = (Bytef *) certdata;

if (inflateInit2(&zs, MAX_WBITS | 16) != Z_OK) {
fprintf(stderr, "Failed to decompress certificate 0.\n");
*decompressed_data_len = 0;
fprintf(stderr, "Failed to initialize certificate decompression.\n");
*certdata_len = 0;
return YKPIV_INVALID_OBJECT;
}
if (inflate(&zs, Z_FINISH) != Z_STREAM_END) {
fprintf(stderr, "Failed to decompress certificate 1.\n");
*decompressed_data_len = 0;
fprintf(stderr, "Failed to decompress certificate.\n");
*certdata_len = 0;
return YKPIV_INVALID_OBJECT;
}
if (inflateEnd(&zs) != Z_OK) {
fprintf(stderr, "Failed to decompress certificate 2.\n");
*decompressed_data_len = 0;
fprintf(stderr, "Failed to finish certificate decompression.\n");
*certdata_len = 0;
return YKPIV_INVALID_OBJECT;
}
*decompressed_data_len = zs.total_out;
*certdata_len = zs.total_out;
} else {
*decompressed_data_len = 0;
memmove(certdata, ptr, len);
*certdata_len = len;
}
return YKPIV_OK;
}
}

static ykpiv_rc _read_certificate(ykpiv_state *state, uint8_t slot, uint8_t *buf, size_t *buf_len) {
ykpiv_rc res = YKPIV_OK;
uint8_t *ptr = NULL;
unsigned long ul_len = (unsigned long)*buf_len;
int object_id = (int)ykpiv_util_slot_object(slot);
size_t offs, len = 0;

if (-1 == object_id) return YKPIV_INVALID_OBJECT;

if (YKPIV_OK == (res = _ykpiv_fetch_object(state, object_id, buf, &ul_len))) {
ptr = buf;

// check that object contents are at least large enough to read the tag
if (ul_len < CB_OBJ_TAG_MIN) {
Expand All @@ -1443,27 +1448,15 @@ uint32_t ykpiv_util_slot_object(uint8_t slot) {

// check that first byte indicates "certificate" type

if (*ptr++ == TAG_CERT) {
offs = _ykpiv_get_length(ptr, buf + ul_len, &len);
if(!offs) {
*buf_len = 0;
return YKPIV_OK;
}
ptr += offs;

unsigned char decompressed_data[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long decompressed_data_len = sizeof (decompressed_data);
if((res = ykpiv_util_decompressed_cert(buf, ul_len, ptr, decompressed_data, &decompressed_data_len)) != YKPIV_OK) {
DBG("could not decompress compressed certificate. Maybe because it was already compressed when imported?");
if (buf[0] == TAG_CERT) {
unsigned char certdata[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long certdata_len = sizeof (certdata);
if ((res = ykpiv_util_get_certdata(buf, ul_len, certdata, &certdata_len)) != YKPIV_OK) {
DBG("Failed to get certificate data");
return res;
}
if (decompressed_data_len > 0) {
memmove(buf, decompressed_data, decompressed_data_len);
*buf_len = decompressed_data_len;
} else {
memmove(buf, ptr, len);
*buf_len = len;
}
memmove(buf, certdata, certdata_len);
*buf_len = certdata_len;
}
} else {
*buf_len = 0;
Expand Down
12 changes: 5 additions & 7 deletions lib/ykpiv.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,16 +344,14 @@ extern "C"
/**
* Decompresses a certificate if it was compressed
*
* @param buf Certificate data
* @param len Length of certificate data
* @param buf_ptr Pointer to where the start reading the certificate data from in buf
* @param decompressed_data Decompressed certificate data
* @param decompressed_data_len Length of decompressed data
* @param buf Fetched certificate data
* @param buf_len Length of fetched certificate data
* @param certdata Raw certificate bytes
* @param certdata_len Length of raw certificate bytes
*
* @return Error code
*/
ykpiv_rc ykpiv_util_decompressed_cert(uint8_t *buf, size_t len, uint8_t *buf_ptr,
unsigned char *decompressed_data, unsigned long *decompressed_data_len);
ykpiv_rc ykpiv_util_get_certdata(uint8_t *buf, size_t buf_len, uint8_t* certdata, unsigned long *certdata_len);
/**
* Write a certificate to a given slot
*
Expand Down
35 changes: 7 additions & 28 deletions tool/yubico-piv-tool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,6 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
unsigned char data[YKPIV_OBJ_MAX_SIZE] = {0};
const unsigned char *ptr = data;
unsigned long len = sizeof(data);
unsigned long offs, cert_len;
X509 *x509 = NULL;
X509_NAME *subj;
BIO *bio = NULL;
Expand All @@ -1566,35 +1565,15 @@ static void print_cert_info(ykpiv_state *state, enum enum_slot slot, const EVP_M
unsigned int md_len = sizeof(data);
const ASN1_TIME *not_before, *not_after;

offs = get_length(ptr, data + len, &cert_len);
if(!offs) {
fprintf(output, "Invalid cert length.\n");
goto cert_out;
unsigned char certdata[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long certdata_len = sizeof (certdata);
if(ykpiv_util_get_certdata(data, len, certdata, &certdata_len) != YKPIV_OK) {
fprintf(stderr, "Failed to get certificate data\n");
return;
}
ptr += offs;
x509 = d2i_X509(NULL, &ptr, cert_len);
if(!x509) {

unsigned char decompressed_data[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long decompressed_data_len = sizeof (decompressed_data);
if(ykpiv_util_decompressed_cert(data, len, (uint8_t*) ptr, decompressed_data, &decompressed_data_len) != YKPIV_OK) {
fprintf(stderr, "could not decompress compressed certificate. Maybe because it was already compressed when imported?\n");
goto cert_out;
}
if(decompressed_data_len > 0) {
const unsigned char *ptr_decompressed = decompressed_data;
x509 = d2i_X509(NULL, &ptr_decompressed, decompressed_data_len);
if(!x509) {
fprintf(output, "Compressed certificate present. Unable to decompress, probably because "
"certificate was imported already compressed.\n");
goto cert_out;
}
const unsigned char *certdata_ptr = certdata;
x509 = d2i_X509(NULL, &certdata_ptr, certdata_len);

} else {
fprintf(output, "Invalid cert data.\n");
goto cert_out;
}
}
{
EVP_PKEY *key = X509_get_pubkey(x509);
if(!key) {
Expand Down
24 changes: 7 additions & 17 deletions ykcs11/openssl_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,27 +108,17 @@ CK_RV do_rsa_encrypt(ykcs11_pkey_t *key, int padding, const ykcs11_md_t* oaep_md
CK_RV do_store_cert(CK_BYTE_PTR data, CK_ULONG len, ykcs11_x509_t **cert) {

const unsigned char *p = data; // Mandatory temp variable required by OpenSSL
unsigned long offs, cert_len;
unsigned long cert_len;

if (*p == TAG_CERT) {
// The certificate is in "PIV" format 0x70 len 0x30 len ...
p++;
offs = get_length(p, data + len, &cert_len);
if(!offs)
return CKR_ARGUMENTS_BAD;
p += offs;

unsigned char decompressed_data[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long decompressed_data_len = sizeof (decompressed_data);
if(ykpiv_util_decompressed_cert(data, len, (uint8_t*) p, decompressed_data, &decompressed_data_len) != YKPIV_OK) {
DBG("could not decompress compressed certificate. Maybe because it was already compressed when imported?");
unsigned char certdata[YKPIV_OBJ_MAX_SIZE * 10] = {0};
unsigned long certdata_len = sizeof (certdata);
if(ykpiv_util_get_certdata(data, len, certdata, &certdata_len) != YKPIV_OK) {
DBG("Failed to get certificate data");
return CKR_DATA_INVALID;
}
if (decompressed_data_len > 0) {
p = decompressed_data;
cert_len = decompressed_data_len;
}

p = certdata;
cert_len = certdata_len;
} else {
// Raw certificate ...
cert_len = len;
Expand Down

0 comments on commit daf69b1

Please sign in to comment.