/* * COPYRIGHT (c) International Business Machines Corp. 2001-2017 * * This program is provided under the terms of the Common Public License, * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this * software constitutes recipient's acceptance of CPL-1.0 terms which can be * found in the file LICENSE file or at * https://opensource.org/licenses/cpl1.0.php */ // ASN.1 encoding/decoding routines // // This code is a mess... // #include #include #include #include #include "pkcs11types.h" #include "p11util.h" #include "defs.h" #include "host_defs.h" #include "h_extern.h" #include "trace.h" // // CK_ULONG ber_encode_INTEGER(CK_BBOOL length_only, CK_BYTE **ber_int, CK_ULONG *ber_int_len, CK_BYTE *data, CK_ULONG data_len) { CK_BYTE *buf = NULL; CK_ULONG len, padding = 0; // ber encoded integers are alway signed. So if the msb of the first byte // is set, this would indicate an negative value if we just copy the // (unsigned) big integer from *data to the ber buffer. So in this case // a preceding 0x00 byte is stored before the actual data. The decode // function does the reverse and may skip this padding. if ((length_only && data_len && (!data || *data & 0x80)) || (data_len && data && *data & 0x80)) padding = 1; // if data_len < 127 use short-form length id // if data_len < 256 use long-form length id with 1-byte length field // if data_len < 65536 use long-form length id with 2-byte length field // if data_len < 16777216 use long-form length id with 3-byte length field // if (data_len + padding < 128) { len = 1 + 1 + padding + data_len; } else if (data_len + padding < 256) { len = 1 + (1 + 1) + padding + data_len; } else if (data_len + padding < (1 << 16)) { len = 1 + (1 + 2) + padding + data_len; } else if (data_len + padding < (1 << 24)) { len = 1 + (1 + 3) + padding + data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *ber_int_len = len; return CKR_OK; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (data_len + padding < 128) { buf[0] = 0x02; buf[1] = data_len + padding; if (padding) { buf[2] = 0x00; if (data && data_len) memcpy(&buf[3], data, data_len); } else { if (data && data_len) memcpy(&buf[2], data, data_len); } *ber_int_len = len; *ber_int = buf; return CKR_OK; } if (data_len + padding < 256) { buf[0] = 0x02; buf[1] = 0x81; buf[2] = data_len + padding; if (padding) { buf[3] = 0x00; if (data && data_len) memcpy(&buf[4], data, data_len); } else { if (data && data_len) memcpy(&buf[3], data, data_len); } *ber_int_len = len; *ber_int = buf; return CKR_OK; } if (data_len + padding < (1 << 16)) { buf[0] = 0x02; buf[1] = 0x82; buf[2] = ((data_len + padding) >> 8) & 0xFF; buf[3] = ((data_len + padding)) & 0xFF; if (padding) { buf[4] = 0x00; if (data && data_len) memcpy(&buf[5], data, data_len); } else { if (data && data_len) memcpy(&buf[4], data, data_len); } *ber_int_len = len; *ber_int = buf; return CKR_OK; } if (data_len + padding < (1 << 24)) { buf[0] = 0x02; buf[1] = 0x83; buf[2] = ((data_len + padding) >> 16) & 0xFF; buf[3] = ((data_len + padding) >> 8) & 0xFF; buf[4] = ((data_len + padding)) & 0xFF; if (padding) { buf[5] = 0x00; if (data) memcpy(&buf[6], data, data_len); } else { if (data) memcpy(&buf[5], data, data_len); } *ber_int_len = len; *ber_int = buf; return CKR_OK; } // we should never reach this // free(buf); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_decode_INTEGER(CK_BYTE *ber_int, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (!ber_int) { TRACE_ERROR("Invalid function argument.\n"); return CKR_FUNCTION_FAILED; } if (ber_int[0] != 0x02) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // ber encoded integers are alway signed. So it may be that the very first // byte is just a padding 0x00 value because the following byte has the msb // set and without the padding the value would indicate a negative value. // However, opencryptoki always stores big integers 'unsigned' meaning // even when the msb is set, there is no preceding 0x00. Even more some // tests may fail e.g. the size in bytes of a modulo big integer should be // modulo bits / 8 which is not true with preceeding 0x00 byte. // short form lengths are easy // if ((ber_int[1] & 0x80) == 0) { len = ber_int[1] & 0x7F; *data = &ber_int[2]; *data_len = len; if (ber_int[2] == 0x00) { *data = &ber_int[3]; *data_len = len - 1; } *field_len = 1 + 1 + len; return CKR_OK; } length_octets = ber_int[1] & 0x7F; if (length_octets == 1) { len = ber_int[2]; *data = &ber_int[3]; *data_len = len; if (ber_int[3] == 0x00) { *data = &ber_int[4]; *data_len = len - 1; } *field_len = 1 + (1 + 1) + len; return CKR_OK; } if (length_octets == 2) { len = ber_int[2]; len = len << 8; len |= ber_int[3]; *data = &ber_int[4]; *data_len = len; if (ber_int[4] == 0x00) { *data = &ber_int[5]; *data_len = len - 1; } *field_len = 1 + (1 + 2) + len; return CKR_OK; } if (length_octets == 3) { len = ber_int[2]; len = len << 8; len |= ber_int[3]; len = len << 8; len |= ber_int[4]; *data = &ber_int[5]; *data_len = len; if (ber_int[5] == 0x00) { *data = &ber_int[6]; *data_len = len - 1; } *field_len = 1 + (1 + 3) + len; return CKR_OK; } // > 3 length octets implies a length > 16MB which isn't possible for // the coprocessor // TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_encode_OCTET_STRING(CK_BBOOL length_only, CK_BYTE **str, CK_ULONG *str_len, CK_BYTE *data, CK_ULONG data_len) { CK_BYTE *buf = NULL; CK_ULONG len; // I only support Primitive encoding for OCTET STRINGS // // if data_len < 128 use short-form length id // if data_len < 256 use long-form length id with 1-byte length field // if data_len < 65536 use long-form length id with 2-byte length field // if (data_len < 128) { len = 1 + 1 + data_len; } else if (data_len < 256) { len = 1 + (1 + 1) + data_len; } else if (data_len < (1 << 16)) { len = 1 + (1 + 2) + data_len; } else if (data_len < (1 << 24)) { len = 1 + (1 + 3) + data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *str_len = len; return CKR_OK; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (data_len < 128) { buf[0] = 0x04; // primitive, OCTET STRING buf[1] = data_len; memcpy(&buf[2], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < 256) { buf[0] = 0x04; // primitive, OCTET STRING buf[1] = 0x81; // length header -- 1 length octets buf[2] = data_len; memcpy(&buf[3], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < (1 << 16)) { buf[0] = 0x04; // primitive, OCTET STRING buf[1] = 0x82; // length header -- 2 length octets buf[2] = (data_len >> 8) & 0xFF; buf[3] = (data_len) & 0xFF; memcpy(&buf[4], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < (1 << 24)) { buf[0] = 0x04; // primitive, OCTET STRING buf[1] = 0x83; // length header -- 3 length octets buf[2] = (data_len >> 16) & 0xFF; buf[3] = (data_len >> 8) & 0xFF; buf[4] = (data_len) & 0xFF; memcpy(&buf[5], data, data_len); *str_len = len; *str = buf; return CKR_OK; } // we should never reach this // free(buf); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_decode_OCTET_STRING(CK_BYTE *str, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; // I only support decoding primitive OCTET STRINGS // if (!str) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (str[0] != 0x04) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // short form lengths are easy // if ((str[1] & 0x80) == 0) { len = str[1] & 0x7F; *data = &str[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = str[1] & 0x7F; if (length_octets == 1) { len = str[2]; *data = &str[3]; *data_len = len; *field_len = 1 + (1 + 1) + len; return CKR_OK; } if (length_octets == 2) { len = str[2]; len = len << 8; len |= str[3]; *data = &str[4]; *data_len = len; *field_len = 1 + (1 + 2) + len; return CKR_OK; } if (length_octets == 3) { len = str[2]; len = len << 8; len |= str[3]; len = len << 8; len |= str[4]; *data = &str[5]; *data_len = len; *field_len = 1 + (1 + 3) + len; return CKR_OK; } // > 3 length octets implies a length > 16MB // TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /** * Here we assume that the indication about unused bits is NOT * part of the data. It will be added by this function. */ CK_ULONG ber_encode_BIT_STRING(CK_BBOOL length_only, CK_BYTE **ber_str, CK_ULONG *ber_str_len, CK_BYTE *data, CK_ULONG data_len, CK_BYTE unused_bits) { CK_BYTE *buf = NULL; CK_ULONG len; // if data_len < 127 use short-form length id // if data_len < 256 use long-form length id with 1-byte length field // if data_len < 65536 use long-form length id with 2-byte length field // if data_len < 16777216 use long-form length id with 3-byte length field if (data_len + 1 < 128) { len = 1 + 1 + 1 + data_len; } else if (data_len + 1 < 256) { len = 1 + (1 + 1) + 1 + data_len; } else if (data_len + 1 < (1 << 16)) { len = 1 + (1 + 2) + 1 + data_len; } else if (data_len + 1 < (1 << 24)) { len = 1 + (1 + 3) + 1 + data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *ber_str_len = len; return CKR_OK; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (data_len + 1 < 128) { buf[0] = 0x03; buf[1] = data_len + 1; buf[2] = unused_bits; if (data && data_len) memcpy(&buf[3], data, data_len); *ber_str_len = len; *ber_str = buf; return CKR_OK; } if (data_len + 1 < 256) { buf[0] = 0x03; buf[1] = 0x81; buf[2] = data_len + 1; buf[3] = unused_bits; if (data && data_len) memcpy(&buf[4], data, data_len); *ber_str_len = len; *ber_str = buf; return CKR_OK; } if (data_len + 1 < (1 << 16)) { buf[0] = 0x03; buf[1] = 0x82; buf[2] = ((data_len + 1) >> 8) & 0xFF; buf[3] = ((data_len + 1)) & 0xFF; buf[4] = unused_bits; if (data && data_len) memcpy(&buf[5], data, data_len); *ber_str_len = len; *ber_str = buf; return CKR_OK; } if (data_len + 1 < (1 << 24)) { buf[0] = 0x03; buf[1] = 0x83; buf[2] = ((data_len + 1) >> 16) & 0xFF; buf[3] = ((data_len + 1) >> 8) & 0xFF; buf[4] = ((data_len + 1)) & 0xFF; buf[5] = unused_bits; if (data) memcpy(&buf[6], data, data_len); *ber_str_len = len; *ber_str = buf; return CKR_OK; } // we should never reach this // free(buf); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /** * Here the 'unused bits' byte is part of the returned decoded data. * The first byte of output parm *data is the number of unused bits and must * be removed later by the calling function. */ CK_RV ber_decode_BIT_STRING(CK_BYTE *str, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (!str) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (str[0] != 0x03) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if ((str[1] & 0x80) == 0) { len = str[1] & 0x7F; *data = &str[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = str[1] & 0x7F; if (length_octets == 1) { len = str[2]; *data = &str[3]; *data_len = len; *field_len = 1 + (1 + 1) + len; return CKR_OK; } if (length_octets == 2) { len = str[2]; len = len << 8; len |= str[3]; *data = &str[4]; *data_len = len; *field_len = 1 + (1 + 2) + len; return CKR_OK; } if (length_octets == 3) { len = str[2]; len = len << 8; len |= str[3]; len = len << 8; len |= str[4]; *data = &str[5]; *data_len = len; *field_len = 1 + (1 + 3) + len; return CKR_OK; } // > 3 length octets implies a length > 16MB // TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_encode_SEQUENCE(CK_BBOOL length_only, CK_BYTE **seq, CK_ULONG *seq_len, CK_BYTE *data, CK_ULONG data_len) { CK_BYTE *buf = NULL; CK_ULONG len; // if data_len < 127 use short-form length id // if data_len < 65536 use long-form length id with 2-byte length field // if (data_len < 128) { len = 1 + 1 + data_len; } else if (data_len < 256) { len = 1 + (1 + 1) + data_len; } else if (data_len < (1 << 16)) { len = 1 + (1 + 2) + data_len; } else if (data_len < (1 << 24)) { len = 1 + (1 + 3) + data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *seq_len = len; return CKR_OK; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (data_len < 128) { buf[0] = 0x30; // constructed, SEQUENCE buf[1] = data_len; memcpy(&buf[2], data, data_len); *seq_len = len; *seq = buf; return CKR_OK; } if (data_len < 256) { buf[0] = 0x30; // constructed, SEQUENCE buf[1] = 0x81; // length header -- 1 length octets buf[2] = data_len; memcpy(&buf[3], data, data_len); *seq_len = len; *seq = buf; return CKR_OK; } if (data_len < (1 << 16)) { buf[0] = 0x30; // constructed, SEQUENCE buf[1] = 0x82; // length header -- 2 length octets buf[2] = (data_len >> 8) & 0xFF; buf[3] = (data_len) & 0xFF; memcpy(&buf[4], data, data_len); *seq_len = len; *seq = buf; return CKR_OK; } if (data_len < (1 << 24)) { buf[0] = 0x30; // constructed, SEQUENCE buf[1] = 0x83; // length header -- 3 length octets buf[2] = (data_len >> 16) & 0xFF; buf[3] = (data_len >> 8) & 0xFF; buf[4] = (data_len) & 0xFF; memcpy(&buf[5], data, data_len); *seq_len = len; *seq = buf; return CKR_OK; } free(buf); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_decode_SEQUENCE(CK_BYTE *seq, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len) { CK_ULONG len, length_octets; if (!seq) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (seq[0] != 0x30) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // short form lengths are easy // if ((seq[1] & 0x80) == 0) { len = seq[1] & 0x7F; *data = &seq[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = seq[1] & 0x7F; if (length_octets == 1) { len = seq[2]; *data = &seq[3]; *data_len = len; *field_len = 1 + (1 + 1) + len; return CKR_OK; } if (length_octets == 2) { len = seq[2]; len = len << 8; len |= seq[3]; *data = &seq[4]; *data_len = len; *field_len = 1 + (1 + 2) + len; return CKR_OK; } if (length_octets == 3) { len = seq[2]; len = len << 8; len |= seq[3]; len = len << 8; len |= seq[4]; *data = &seq[5]; *data_len = len; *field_len = 1 + (1 + 3) + len; return CKR_OK; } // > 3 length octets implies a length > 16MB // TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // CK_RV ber_encode_CHOICE(CK_BBOOL length_only, CK_BYTE option, CK_BYTE **str, CK_ULONG *str_len, CK_BYTE *data, CK_ULONG data_len) { CK_BYTE *buf = NULL; CK_ULONG len; /* * if data_len < 127 use short-form length id * if data_len < 65536 use long-form length id with 2-byte length field */ if (data_len < 128) { len = 1 + 1 + data_len; } else if (data_len < 256) { len = 1 + (1 + 1) + data_len; } else if (data_len < (1 << 16)) { len = 1 + (1 + 2) + data_len; } else if (data_len < (1 << 24)) { len = 1 + (1 + 3) + data_len; } else { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { *str_len = len; return CKR_OK; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } if (data_len < 128) { buf[0] = 0xA0 | option; // constructed, CHOICE buf[1] = data_len; memcpy(&buf[2], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < 256) { buf[0] = 0xA0 | option; // constructed, CHOICE buf[1] = 0x81; // length header -- 1 length octets buf[2] = data_len; memcpy(&buf[3], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < (1 << 16)) { buf[0] = 0xA0 | option; // constructed, CHOICE buf[1] = 0x82; // length header -- 2 length octets buf[2] = (data_len >> 8) & 0xFF; buf[3] = (data_len) & 0xFF; memcpy(&buf[4], data, data_len); *str_len = len; *str = buf; return CKR_OK; } if (data_len < (1 << 24)) { buf[0] = 0xA0 | option; // constructed, CHOICE buf[1] = 0x83; // length header -- 3 length octets buf[2] = (data_len >> 16) & 0xFF; buf[3] = (data_len >> 8) & 0xFF; buf[4] = (data_len) & 0xFF; memcpy(&buf[5], data, data_len); *str_len = len; *str = buf; return CKR_OK; } free(buf); TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // PrivateKeyInfo ::= SEQUENCE { // version Version -- always '0' for now // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier // privateKey PrivateKey // attributes // } // CK_RV ber_decode_CHOICE(CK_BYTE *choice, CK_BYTE **data, CK_ULONG *data_len, CK_ULONG *field_len, CK_ULONG *option) { CK_ULONG len, length_octets; if (!choice) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } if ((choice[0] & 0xE0) != 0xA0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } *option = choice[0] & 0x1F; // short form lengths are easy // if ((choice[1] & 0x80) == 0) { len = choice[1] & 0x7F; *data = &choice[2]; *data_len = len; *field_len = 1 + (1) + len; return CKR_OK; } length_octets = choice[1] & 0x7F; if (length_octets == 1) { len = choice[2]; *data = &choice[3]; *data_len = len; *field_len = 1 + (1 + 1) + len; return CKR_OK; } if (length_octets == 2) { len = choice[2]; len = len << 8; len |= choice[3]; *data = &choice[4]; *data_len = len; *field_len = 1 + (1 + 2) + len; return CKR_OK; } if (length_octets == 3) { len = choice[2]; len = len << 8; len |= choice[3]; len = len << 8; len |= choice[4]; *data = &choice[5]; *data_len = len; *field_len = 1 + (1 + 3) + len; return CKR_OK; } // > 3 length octets implies a length > 16MB // TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // PrivateKeyInfo ::= SEQUENCE { // version Version -- always '0' for now // privateKeyAlgorithm PrivateKeyAlgorithmIdentifier // privateKey PrivateKey // attributes // } // CK_RV ber_encode_PrivateKeyInfo(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, const CK_BYTE *algorithm_id, const CK_ULONG algorithm_id_len, CK_BYTE *priv_key, CK_ULONG priv_key_len) { CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_BYTE version[] = { 0 }; CK_ULONG len, total; CK_RV rc; len = 0; rc = ber_encode_INTEGER(TRUE, NULL, &total, version, sizeof(version)); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return rc; } else { len += total; } len += algorithm_id_len; rc = ber_encode_OCTET_STRING(TRUE, NULL, &total, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); return rc; } len += total; // for this stuff, attributes can be suppressed. // if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len); if (rc == CKR_OK) *data_len = total; if (rc != CKR_OK) TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } len = 0; rc = ber_encode_INTEGER(FALSE, &tmp, &total, version, sizeof(version)); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + len, tmp, total); len += total; free(tmp); } memcpy(buf + len, algorithm_id, algorithm_id_len); len += algorithm_id_len; rc = ber_encode_OCTET_STRING(FALSE, &tmp, &total, priv_key, priv_key_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto error; } memcpy(buf + len, tmp, total); len += total; free(tmp); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, len); if (rc != CKR_OK) TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); error: free(buf); return rc; } // // CK_RV ber_decode_PrivateKeyInfo(CK_BYTE *data, CK_ULONG data_len, CK_BYTE **algorithm, CK_ULONG *alg_len, CK_BYTE **priv_key) { CK_BYTE *buf = NULL; CK_BYTE *alg = NULL; CK_BYTE *ver = NULL; CK_ULONG buf_len, offset, len, field_len; CK_RV rc; if (!data || (data_len == 0)) { TRACE_ERROR("Invalid function arguments.\n"); return CKR_FUNCTION_FAILED; } rc = ber_decode_SEQUENCE(data, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } // version -- we just ignore this // offset = 0; rc = ber_decode_INTEGER(buf + offset, &ver, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } offset += field_len; // 'buf' is now pointing to the PrivateKeyAlgorithmIdentifier // rc = ber_decode_SEQUENCE(buf + offset, &alg, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } *algorithm = alg; *alg_len = len; rc = ber_decode_OCTET_STRING(alg + len, priv_key, &buf_len, &field_len); if (rc != CKR_OK) TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); return rc; } /*Extract data from an SPKI * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } */ CK_RV ber_decode_SPKI(CK_BYTE *spki, CK_BYTE **alg_oid, CK_ULONG *alg_oid_len, CK_BYTE **param, CK_ULONG *param_len, CK_BYTE **key, CK_ULONG *key_len) { CK_BYTE *out_seq, *id_seq, *bit_str; CK_BYTE *data; CK_ULONG data_len; CK_ULONG field_len; CK_RV rc; *alg_oid_len = 0; *param_len = 0; *key_len = 0; out_seq = spki; rc = ber_decode_SEQUENCE(out_seq, &data, &data_len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE #1 failed rc=0x%lx\n", __func__, rc); return rc; } id_seq = out_seq + field_len - data_len; /* get id seq */ rc = ber_decode_SEQUENCE(id_seq, &data, &data_len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_SEQUENCE #2 failed rc=0x%lx\n", __func__, rc); return rc; } *alg_oid = data; *alg_oid_len = data[1] + 2; *param = data + *alg_oid_len; *param_len = data_len - *alg_oid_len; bit_str = id_seq + field_len; /* get bitstring */ rc = ber_decode_BIT_STRING(bit_str, key, key_len, &field_len); if (rc != CKR_OK) { TRACE_ERROR("%s ber_decode_BIT_STRING failed rc=0x%lx\n", __func__, rc); return rc; } (*key_len)--; /* remove 'unused bits' byte from length */ (*key)++; return CKR_OK; } // RSAPrivateKey ::= SEQUENCE { // version Version -- always '0' for now // modulus INTEGER // publicExponent INTEGER // privateExponent INTEGER // prime1 INTEGER // prime2 INTEGER // exponent1 INTEGER // exponent2 INTEGER // coefficient INTEGER // } // CK_RV ber_encode_RSAPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *publ_exp, CK_ATTRIBUTE *priv_exp, CK_ATTRIBUTE *prime1, CK_ATTRIBUTE *prime2, CK_ATTRIBUTE *exponent1, CK_ATTRIBUTE *exponent2, CK_ATTRIBUTE *coeff) { CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; CK_ULONG len, offset; CK_BYTE version[] = { 0 }; CK_RV rc; offset = 0; rc = 0; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, modulus->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, publ_exp->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_exp->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime1->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime2->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, exponent1->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, exponent2->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, coeff->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, ber_AlgIdRSAEncryptionLen, NULL, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return rc; } buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } offset = 0; rc = 0; rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) modulus + sizeof(CK_ATTRIBUTE), modulus->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) publ_exp + sizeof(CK_ATTRIBUTE), publ_exp->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) priv_exp + sizeof(CK_ATTRIBUTE), priv_exp->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) prime1 + sizeof(CK_ATTRIBUTE), prime1->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) prime2 + sizeof(CK_ATTRIBUTE), prime2->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) exponent1 + sizeof(CK_ATTRIBUTE), exponent1->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) exponent2 + sizeof(CK_ATTRIBUTE), exponent2->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) coeff + sizeof(CK_ATTRIBUTE), coeff->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, ber_AlgIdRSAEncryption, ber_AlgIdRSAEncryptionLen, buf2, len); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); } error: if (buf2) free(buf2); if (buf) free(buf); return rc; } // // CK_RV ber_decode_RSAPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **modulus, CK_ATTRIBUTE **publ_exp, CK_ATTRIBUTE **priv_exp, CK_ATTRIBUTE **prime1, CK_ATTRIBUTE **prime2, CK_ATTRIBUTE **exponent1, CK_ATTRIBUTE **exponent2, CK_ATTRIBUTE **coeff) { CK_ATTRIBUTE *n_attr = NULL; CK_ATTRIBUTE *e_attr = NULL; CK_ATTRIBUTE *d_attr = NULL; CK_ATTRIBUTE *p_attr = NULL; CK_ATTRIBUTE *q_attr = NULL; CK_ATTRIBUTE *e1_attr = NULL; CK_ATTRIBUTE *e2_attr = NULL; CK_ATTRIBUTE *coeff_attr = NULL; CK_BYTE *alg = NULL; CK_BYTE *rsa_priv_key = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_ULONG offset, buf_len, field_len, len; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &rsa_priv_key); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } // make sure we're dealing with an RSA key // if (memcmp(alg, ber_rsaEncryption, ber_rsaEncryptionLen) != 0) { // probably ought to use a different error TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = ber_decode_SEQUENCE(rsa_priv_key, &buf, &buf_len, &field_len); if (rc != CKR_OK) return rc; // parse the RSAPrivateKey // offset = 0; // Version // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // modulus // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // public exponent // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // private exponent // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // prime #1 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // prime #2 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // exponent #1 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // exponent #2 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // coefficient // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; if (offset > buf_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // it looks okay. build the attributes // offset = 0; // skip the version // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // modulus // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_MODULUS, tmp, len, &n_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // public exponent // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PUBLIC_EXPONENT, tmp, len, &e_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // private exponent // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PRIVATE_EXPONENT, tmp, len, &d_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // prime #1 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PRIME_1, tmp, len, &p_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // prime #2 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PRIME_2, tmp, len, &q_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // exponent #1 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_EXPONENT_1, tmp, len, &e1_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // exponent #2 // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_EXPONENT_2, tmp, len, &e2_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // coefficient // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_COEFFICIENT, tmp, len, &coeff_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += len; } *priv_exp = d_attr; *prime1 = p_attr; *prime2 = q_attr; *exponent1 = e1_attr; *exponent2 = e2_attr; *coeff = coeff_attr; *modulus = n_attr; *publ_exp = e_attr; return CKR_OK; cleanup: if (n_attr) free(n_attr); if (e_attr) free(e_attr); if (d_attr) free(d_attr); if (p_attr) free(p_attr); if (q_attr) free(q_attr); if (e1_attr) free(e1_attr); if (e2_attr) free(e2_attr); if (coeff_attr) free(coeff_attr); return rc; } CK_RV ber_encode_RSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *modulus, CK_ATTRIBUTE *publ_exp) { CK_ULONG len, offset, total, total_len; CK_RV rc; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; CK_BYTE *buf3 = NULL; BerValue *val; BerElement *ber; UNUSED(length_only); offset = 0; rc = 0; total_len = ber_AlgIdRSAEncryptionLen; total = 0; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, modulus->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, publ_exp->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } offset = 0; rc = 0; rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) modulus + sizeof(CK_ATTRIBUTE), modulus->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_INTEGER(FALSE, &buf2, &len, (CK_BYTE *) publ_exp + sizeof(CK_ATTRIBUTE), publ_exp->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } /* length of outer sequence */ rc = ber_encode_OCTET_STRING(TRUE, NULL, &total, buf2, len); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Oct_Str failed with rc=0x%lx\n", __func__, rc); return rc; } else { total_len += total + 1; } /* mem for outer sequence */ buf3 = (CK_BYTE *) malloc(total_len); if (!buf3) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } total_len = 0; /* copy alg id */ memcpy(buf3 + total_len, ber_AlgIdRSAEncryption, ber_AlgIdRSAEncryptionLen); total_len += ber_AlgIdRSAEncryptionLen; /* need a bitstring */ ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)buf2, len * 8, 0x03); rc = ber_flatten(ber, &val); memcpy(buf3 + total_len, val->bv_val, val->bv_len); total_len += val->bv_len; rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf3, total_len); if (rc != CKR_OK) TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } CK_RV ber_decode_RSAPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **modulus, CK_ATTRIBUTE **publ_exp) { CK_ATTRIBUTE *modulus_attr = NULL; CK_ATTRIBUTE *publ_exp_attr = NULL; CK_BYTE *algid_RSABase = NULL; CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *val = NULL; CK_ULONG val_len; CK_BYTE *seq; CK_ULONG seq_len; CK_BYTE *mod; CK_ULONG mod_len; CK_BYTE *exp; CK_ULONG exp_len; CK_ULONG field_len, offset, len; CK_RV rc; UNUSED(data_len); // XXX can this parameter be removed ? rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } /* * Make sure we're dealing with an DH key. */ rc = ber_decode_SEQUENCE((CK_BYTE *)ber_AlgIdRSAEncryption, &algid_RSABase, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } if (memcmp(algid, algid_RSABase, len) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = ber_decode_SEQUENCE(val, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, &mod, &mod_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } offset = field_len; rc = ber_decode_INTEGER(seq + offset, &exp, &exp_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } // build modulus attribute rc = build_attribute(CKA_MODULUS, mod, mod_len, &modulus_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build base attribute rc = build_attribute(CKA_PUBLIC_EXPONENT, exp, exp_len, &publ_exp_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *modulus = modulus_attr; *publ_exp = publ_exp_attr; return CKR_OK; cleanup: if (modulus_attr) free(modulus_attr); if (publ_exp_attr) free(publ_exp_attr); return rc; } // DSA is a little different from RSA // // DSAPrivateKey ::= INTEGER // // The 'parameters' field of the AlgorithmIdentifier are as follows: // // DSSParameters ::= SEQUENCE { // prime1 INTEGER // prime2 INTEGER // base INTEGER // } // CK_RV ber_encode_DSAPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *prime1, CK_ATTRIBUTE *prime2, CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key) { CK_BYTE *param = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_BYTE *alg = NULL; CK_ULONG offset, len, param_len; CK_ULONG alg_len; CK_RV rc; // build the DSS parameters first // offset = 0; rc = 0; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime1->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime2->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, ¶m_len, NULL, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } rc = ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_key->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return rc; } rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, ber_idDSALen + param_len, NULL, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); } return rc; } // 'buf' will be the sequence data for the AlgorithmIdentifyer::parameter // buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } len = 0; offset = 0; rc = ber_encode_INTEGER(FALSE, &tmp, &len, (CK_BYTE *) prime1 + sizeof(CK_ATTRIBUTE), prime1->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + offset, tmp, len); offset += len; free(tmp); tmp = NULL; } rc = ber_encode_INTEGER(FALSE, &tmp, &len, (CK_BYTE *) prime2 + sizeof(CK_ATTRIBUTE), prime2->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + offset, tmp, len); offset += len; free(tmp); tmp = NULL; } rc = ber_encode_INTEGER(FALSE, &tmp, &len, (CK_BYTE *) base + sizeof(CK_ATTRIBUTE), base->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + offset, tmp, len); offset += len; free(tmp); tmp = NULL; } rc = ber_encode_SEQUENCE(FALSE, ¶m, ¶m_len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); free(buf); return rc; } free(buf); buf = NULL; // Build the DSA AlgorithmIdentifier // // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER // parameters ANY DEFINED BY algorithm OPTIONAL // } // len = ber_idDSALen + param_len; buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto error; } memcpy(buf, ber_idDSA, ber_idDSALen); memcpy(buf + ber_idDSALen, param, param_len); free(param); param = NULL; rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, buf, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); goto error; } free(buf); buf = NULL; // build the private key INTEGER // rc = ber_encode_INTEGER(FALSE, &buf, &len, (CK_BYTE *) priv_key + sizeof(CK_ATTRIBUTE), priv_key->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, buf, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg) free(alg); if (buf) free(buf); if (param) free(param); if (tmp) free(tmp); return rc; } // // CK_RV ber_decode_DSAPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **prime, CK_ATTRIBUTE **subprime, CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key) { CK_ATTRIBUTE *p_attr = NULL; CK_ATTRIBUTE *q_attr = NULL; CK_ATTRIBUTE *g_attr = NULL; CK_ATTRIBUTE *x_attr = NULL; CK_BYTE *alg = NULL; CK_BYTE *buf = NULL; CK_BYTE *dsakey = NULL; CK_BYTE *tmp = NULL; CK_ULONG buf_len, field_len, len, offset; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dsakey); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } // make sure we're dealing with a DSA key. just compare the OBJECT // IDENTIFIER // if (memcmp(alg, ber_idDSA, ber_idDSALen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // extract the parameter data into ATTRIBUTES // rc = ber_decode_SEQUENCE(alg + ber_idDSALen, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } offset = 0; // prime // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // subprime // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // base // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; if (offset > buf_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // // it looks okay. build the attributes // offset = 0; // prime // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PRIME, tmp, len, &p_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // subprime // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_SUBPRIME, tmp, len, &q_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // base // rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_BASE, tmp, len, &g_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // now get the private key // rc = ber_decode_INTEGER(dsakey, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_VALUE, tmp, len, &x_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } *prime = p_attr; *subprime = q_attr; *base = g_attr; *priv_key = x_attr; return CKR_OK; cleanup: if (p_attr) free(p_attr); if (q_attr) free(q_attr); if (g_attr) free(g_attr); if (x_attr) free(x_attr); return rc; } CK_RV ber_encode_DSAPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *prime, CK_ATTRIBUTE *subprime, CK_ATTRIBUTE *base, CK_ATTRIBUTE *value) { CK_ULONG len, parm_len, id_len, pub_len, offset, total; CK_RV rc = 0; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; BerValue *val; BerElement *ber; /* Calculate the BER container length * * SPKI := SEQUENCE { * SEQUENCE { * OID * Parameters * } * BITSTRING public key * } */ offset = 0; rc = 0; total = 0; parm_len = 0; id_len = 0; pub_len = 0; /* OID and parameters */ rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, subprime->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); offset += len; rc |= ber_encode_SEQUENCE(TRUE, NULL, &parm_len, NULL, offset); rc |= ber_encode_SEQUENCE(TRUE, NULL, &id_len, NULL, ber_idDSALen + parm_len); /* public key */ rc |= ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); rc = ber_flatten(ber, &val); pub_len = val->bv_len; ber_free(ber, 1); free(buf); rc |= ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, id_len + pub_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only == TRUE) { *data_len = total; return rc; } buf = (CK_BYTE *) malloc(id_len + pub_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } /* Parameters */ offset = 0; rc = ber_encode_INTEGER(FALSE, &buf2, &len, prime->pValue, prime->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_INTEGER(FALSE, &buf2, &len, subprime->pValue, subprime->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_INTEGER(FALSE, &buf2, &len, base->pValue, base->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &parm_len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } /* OID and parameters */ memcpy(buf, ber_idDSA, ber_idDSALen); memcpy(buf + ber_idDSALen, buf2, parm_len); free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &id_len, buf, ber_idDSALen + parm_len); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } free(buf); /* public key */ rc = ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); rc = ber_flatten(ber, &val); free(buf); buf = (CK_BYTE *) malloc(id_len + val->bv_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(buf, buf2, id_len); memcpy(buf + id_len, val->bv_val, val->bv_len); free(buf2); ber_free(ber, 1); /* outer sequence */ rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, id_len + pub_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } free(buf); return rc; } CK_RV ber_decode_DSAPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **prime, CK_ATTRIBUTE **subprime, CK_ATTRIBUTE **base, CK_ATTRIBUTE **value) { CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *subprime_attr = NULL; CK_ATTRIBUTE *base_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *val = NULL; CK_ULONG val_len; CK_BYTE *seq; CK_ULONG seq_len; CK_BYTE *p; CK_ULONG p_len; CK_BYTE *sp; CK_ULONG sp_len; CK_BYTE *b; CK_ULONG b_len; CK_ULONG field_len, offset; CK_RV rc; UNUSED(data_len); // XXX can this parameter be removed ? rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } /* * Make sure we're dealing with an DSA key. */ if (memcmp(algid, ber_idDSA, ber_idDSALen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = ber_decode_SEQUENCE(param, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, &p, &p_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } offset = field_len; rc = ber_decode_INTEGER(seq + offset, &sp, &sp_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } offset += field_len; rc = ber_decode_INTEGER(seq + offset, &b, &b_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } // build prime attribute rc = build_attribute(CKA_PRIME, p, p_len, &prime_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build subprime attribute rc = build_attribute(CKA_SUBPRIME, sp, sp_len, &subprime_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build base attribute rc = build_attribute(CKA_BASE, b, b_len, &base_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build value attribute rc = build_attribute(CKA_VALUE, val, val_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *prime = prime_attr; *subprime = subprime_attr; *base = base_attr; *value = value_attr; return CKR_OK; cleanup: if (prime_attr) free(prime_attr); if (subprime_attr) free(subprime_attr); if (base_attr) free(base_attr); if (value_attr) free(value_attr); return rc; } /* * ECC Functions */ // // // // CK_RV der_encode_ECPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *params, CK_ATTRIBUTE *point, CK_ATTRIBUTE *pubkey) { CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; CK_ULONG len, offset = 0; CK_BYTE version[] = { 1 }; // ecPrivkeyVer1 CK_BYTE der_AlgIdEC[der_AlgIdECBaseLen + params->ulValueLen]; CK_ULONG der_AlgIdECLen = sizeof(der_AlgIdEC); CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; BerElement *ber; BerValue *val; CK_RV rc = 0; /* Calculate BER encoding length * Inner SEQUENCE of * Integer (version), OCTET STRING (private key) * and CHOICE [1] BIT STRING (public key) */ // version rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); offset += len; // private key octet rc |= ber_encode_OCTET_STRING(TRUE, NULL, &len, NULL, point->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_DEVEL("der encoding failed\n"); return CKR_FUNCTION_FAILED; } // public key bit string if (pubkey && pubkey->pValue) { rc = ber_decode_OCTET_STRING(pubkey->pValue, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || pubkey->ulValueLen != field_len) { TRACE_DEVEL("ber decoding of public key failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); rc = ber_flatten(ber, &val); ber_encode_CHOICE(TRUE, 1, &buf2, &len, (CK_BYTE *)val->bv_val, val->bv_len); offset += len; ber_free(ber, 1); } if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, der_AlgIdECLen, NULL, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return rc; } /* Now starting with the real data */ buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } offset = 0; rc = 0; rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } rc = ber_encode_OCTET_STRING(FALSE, &buf2, &len, (CK_BYTE *) point + sizeof(CK_ATTRIBUTE), point->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (buf2 != NULL) { memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } /* generate optional bit-string of public key */ if (pubkey && pubkey->pValue) { rc = ber_decode_OCTET_STRING(pubkey->pValue, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || pubkey->ulValueLen != field_len) { TRACE_DEVEL("ber decoding of public key failed\n"); return CKR_ATTRIBUTE_VALUE_INVALID; } ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); rc = ber_flatten(ber, &val); ber_encode_CHOICE(FALSE, 1, &buf2, &len, (CK_BYTE *)val->bv_val, val->bv_len); memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; ber_free(ber, 1); } rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); goto error; } /* concatenate EC algorithm-id + specific curve id */ memcpy(der_AlgIdEC, der_AlgIdECBase, der_AlgIdECBaseLen); memcpy(der_AlgIdEC + der_AlgIdECBaseLen, params->pValue, params->ulValueLen); /* adjust length field */ der_AlgIdEC[1] = der_AlgIdEC[1] + params->ulValueLen; rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, der_AlgIdEC, der_AlgIdECLen, buf2, len); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); } error: if (buf2) free(buf2); if (buf) free(buf); return rc; } // // From RFC 5915: // // ECPrivateKey ::= SEQUENCE { // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), // privateKey OCTET STRING, // parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, // publicKey [1] BIT STRING OPTIONAL // } // CK_RV der_decode_ECPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **params, CK_ATTRIBUTE **pub_key, CK_ATTRIBUTE **priv_key) { CK_ATTRIBUTE *pub_attr = NULL; CK_ATTRIBUTE *priv_attr = NULL; CK_ATTRIBUTE *parm_attr = NULL; CK_BYTE *alg = NULL; CK_BYTE *buf = NULL; CK_BYTE *priv_buf = NULL; CK_BYTE *pub_buf = NULL; CK_BYTE *parm_buf = NULL; CK_BYTE *eckey = NULL; CK_BYTE *version = NULL; CK_BYTE *choice = NULL; CK_ULONG version_len, alg_len, priv_len, pub_len, parm_len, buf_len; CK_ULONG buf_offset, field_len, offset, choice_len, option; CK_ULONG pubkey_available = 0; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; CK_RV rc; /* * For unwrapping, the data passed to this function may be larger than the * actual sequence, due to padding. So look at the data only up to the * length in the first SEQUENCE. * Since an EC private key may include an optional public key, we need to * know the actual length to be able to find out of the optional public key * is present or not. */ rc = ber_decode_SEQUENCE(data, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } if (field_len > data_len) { TRACE_DEVEL("passed data is too short\n"); return CKR_FUNCTION_FAILED; } data_len = field_len; /* Decode PrivateKeyInfo into alg and eckey */ rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &alg_len, &eckey); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } /* Check OBJECT IDENTIFIER to make sure this is an EC key */ if (memcmp(alg, ber_idEC, ber_idECLen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode the ecdhkey into buf */ rc = ber_decode_SEQUENCE(eckey, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } offset = 0; /* Decode version (INTEGER) */ rc = ber_decode_INTEGER(buf + offset, &version, &version_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; /* Decode private key (OCTET_STRING) */ rc = ber_decode_OCTET_STRING(buf + offset, &priv_buf, &priv_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_OCTET_STRING failed\n"); goto cleanup; } offset += field_len; /* Check if there is an optional public key */ buf_offset = buf - data; if (buf_offset + offset < data_len) { /* Decode CHOICE */ rc = ber_decode_CHOICE(buf + offset, &choice, &choice_len, &field_len, &option); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_CHOICE failed\n"); goto cleanup; } offset += field_len - choice_len; /* Decode public key (BIT_STRING) according to option */ switch (option) { case 0: /* parameters [0] ECParameters {{ NamedCurve }} OPTIONAL * These params, if available, are assumed to be the same as algo * above, so nothing to do here. */ break; case 1: /* publicKey [1] BIT STRING OPTIONAL */ rc = ber_decode_BIT_STRING(buf + offset, &pub_buf, &pub_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING failed\n"); goto cleanup; } pubkey_available = 1; break; default: TRACE_DEVEL("ber_decode_CHOICE returned invalid or unsupported " "option %ld\n", option); goto cleanup; } } /* Now build attribute for CKA_ECDSA_PARAMS */ parm_buf = alg + ber_idECLen; parm_len = alg_len - ber_idECLen; rc = build_attribute(CKA_ECDSA_PARAMS, parm_buf, parm_len, &parm_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for CKA_ECDSA_PARAMS failed\n"); goto cleanup; } /* Build attr for public key as BER encoded OCTET STRING */ if (pubkey_available) { rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, pub_buf, pub_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto cleanup; } rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &pub_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for public key failed\n"); goto cleanup; } } /* Build attr for private key */ rc = build_attribute(CKA_VALUE, priv_buf, priv_len, &priv_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for private key failed\n"); goto cleanup; } *pub_key = pub_attr; // may be NULL if no BIT_STRING available *priv_key = priv_attr; *params = parm_attr; if (ecpoint) free(ecpoint); return CKR_OK; cleanup: if (pub_attr) free(pub_attr); if (priv_attr) free(priv_attr); if (parm_attr) free(parm_attr); if (ecpoint) free(ecpoint); return rc; } CK_RV ber_encode_ECPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *params, CK_ATTRIBUTE *point) { CK_ULONG len, total; CK_ULONG algid_len = der_AlgIdECBaseLen + params->ulValueLen; CK_RV rc = 0; CK_BYTE *buf = NULL; BerValue *val; BerElement *ber; CK_BYTE *ecpoint; CK_ULONG ecpoint_len, field_len; /* CKA_EC_POINT is an BER encoded OCTET STRING. Extract it. */ rc = ber_decode_OCTET_STRING((CK_BYTE *)point->pValue, &ecpoint, &ecpoint_len, &field_len); if (rc != CKR_OK || point->ulValueLen != field_len) { TRACE_DEVEL("%s ber_decode_OCTET_STRING failed\n", __func__); return CKR_ATTRIBUTE_VALUE_INVALID; } /* Calculate the BER container length * * SPKI := SEQUENCE { * SEQUENCE { * OID * Parameters * } * BITSTRING public key * } */ rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, algid_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); return rc; } /* public key */ ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); rc = ber_flatten(ber, &val); rc = ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, len + val->bv_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); return rc; } ber_free(ber, 1); if (length_only == TRUE) { *data_len = total; return rc; } /* Now compute with real data */ buf = (CK_BYTE *) malloc(total); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(buf, der_AlgIdECBase, der_AlgIdECBaseLen); memcpy(buf + der_AlgIdECBaseLen, params->pValue, params->ulValueLen); buf[1] += params->ulValueLen; /* generate bitstring */ ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)ecpoint, ecpoint_len * 8, 0x03); rc = ber_flatten(ber, &val); memcpy(buf + der_AlgIdECBaseLen + params->ulValueLen, val->bv_val, val->bv_len); ber_free(ber, 1); rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, der_AlgIdECBaseLen + params->ulValueLen + val->bv_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } free(buf); return rc; } /* * ASN.1 type PrivateKeyInfo ::= SEQUENCE { * version Version * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier * privateKey PrivateKey * attributes OPTIONAL * } * * Where PrivateKey is defined as follows for EC: * * ASN.1 type RSAPrivateKey * * ECPrivateKey ::= SEQUENCE { * version Version * privateKey OCTET STRING * parameters [0] ECParameters (OPTIONAL) * publicKey [1] BIT STRING (OPTIONAL) * } */ CK_RV der_decode_ECPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **ec_params, CK_ATTRIBUTE **ec_point) { CK_ATTRIBUTE *params_attr = NULL; CK_ATTRIBUTE *point_attr = NULL; CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *algid_ECBase = NULL; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *point = NULL; CK_ULONG point_len; CK_BYTE *ecpoint = NULL; CK_ULONG ecpoint_len; CK_ULONG field_len, len; CK_RV rc; UNUSED(data_len); // XXX can this parameter be removed ? rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, &point, &point_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } /* * Make sure we're dealing with an EC key. * Extract base alg-id of DER encoded EC byte string * and compare against the decoded alg-id from the inner sequence */ rc = ber_decode_SEQUENCE((CK_BYTE *)der_AlgIdECBase, &algid_ECBase, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } if (memcmp(algid, algid_ECBase, len) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // build ec-parameter attribute rc = build_attribute(CKA_EC_PARAMS, param, param_len, ¶ms_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } /* build ec-point attribute as BER encoded OCTET STRING */ rc = ber_encode_OCTET_STRING(FALSE, &ecpoint, &ecpoint_len, point, point_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_OCTET_STRING failed\n"); goto cleanup; } rc = build_attribute(CKA_EC_POINT, ecpoint, ecpoint_len, &point_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } free(ecpoint); *ec_params = params_attr; *ec_point = point_attr; return CKR_OK; cleanup: if (params_attr) free(params_attr); if (point_attr) free(point_attr); if (ecpoint) free(ecpoint); return rc; } // DH is a little different from RSA // // DHPrivateKey ::= INTEGER // // The 'parameters' field of the AlgorithmIdentifier are as follows: // // DSSParameters ::= SEQUENCE { // prime INTEGER // base INTEGER // } // CK_RV ber_encode_DHPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *prime, CK_ATTRIBUTE *base, CK_ATTRIBUTE *priv_key) { CK_BYTE *param = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_BYTE *alg = NULL; CK_ULONG offset, len, param_len; CK_ULONG alg_len; CK_RV rc; // build the DSS parameters first offset = 0; rc = 0; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, ¶m_len, NULL, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } rc = ber_encode_INTEGER(TRUE, NULL, &len, NULL, priv_key->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); return rc; } rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, ber_idDHLen + param_len, NULL, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); } return rc; } // 'buf' will be the sequence data for the AlgorithmIdentifyer::parameter buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } len = 0; offset = 0; rc = ber_encode_INTEGER(FALSE, &tmp, &len, prime->pValue, prime->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + offset, tmp, len); offset += len; free(tmp); tmp = NULL; } rc = ber_encode_INTEGER(FALSE, &tmp, &len, base->pValue, base->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } if (tmp != NULL) { memcpy(buf + offset, tmp, len); offset += len; free(tmp); tmp = NULL; } rc = ber_encode_SEQUENCE(FALSE, ¶m, ¶m_len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); free(buf); return rc; } free(buf); buf = NULL; // Build the DSA AlgorithmIdentifier // // AlgorithmIdentifier ::= SEQUENCE { // algorithm OBJECT IDENTIFIER // parameters ANY DEFINED BY algorithm OPTIONAL // } // len = ber_idDHLen + param_len; buf = (CK_BYTE *) malloc(len); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); goto error; } memcpy(buf, ber_idDH, ber_idDHLen); memcpy(buf + ber_idDHLen, param, param_len); free(param); param = NULL; rc = ber_encode_SEQUENCE(FALSE, &alg, &alg_len, buf, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); goto error; } free(buf); buf = NULL; // build the private key INTEGER rc = ber_encode_INTEGER(FALSE, &buf, &len, priv_key->pValue, priv_key->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_INTEGER failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, alg, alg_len, buf, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); goto error; } error: if (alg) free(alg); if (buf) free(buf); if (param) free(param); if (tmp) free(tmp); return rc; } // // CK_RV ber_decode_DHPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **prime, CK_ATTRIBUTE **base, CK_ATTRIBUTE **priv_key) { CK_ATTRIBUTE *p_attr = NULL; CK_ATTRIBUTE *g_attr = NULL; CK_ATTRIBUTE *x_attr = NULL; CK_BYTE *alg = NULL; CK_BYTE *buf = NULL; CK_BYTE *dhkey = NULL; CK_BYTE *tmp = NULL; CK_ULONG buf_len, field_len, len, offset; CK_RV rc; rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dhkey); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } // make sure we're dealing with a DH key. just compare the OBJECT // IDENTIFIER if (memcmp(alg, ber_idDH, ber_idDHLen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // extract the parameter data into ATTRIBUTES // rc = ber_decode_SEQUENCE(alg + ber_idDSALen, &buf, &buf_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } offset = 0; // prime rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; // base rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; if (offset > buf_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } // it looks okay. build the attributes offset = 0; // prime rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_PRIME, tmp, len, &p_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // base rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_BASE, tmp, len, &g_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } // now get the private key rc = ber_decode_INTEGER(dhkey, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } else { rc = build_attribute(CKA_VALUE, tmp, len, &x_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } offset += field_len; } *prime = p_attr; *base = g_attr; *priv_key = x_attr; return CKR_OK; cleanup: if (p_attr) free(p_attr); if (g_attr) free(g_attr); if (x_attr) free(x_attr); return rc; } CK_RV ber_encode_DHPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *prime, CK_ATTRIBUTE *base, CK_ATTRIBUTE *value) { CK_ULONG len, parm_len, id_len, pub_len, offset, total; CK_RV rc = 0; CK_BYTE *buf = NULL; CK_BYTE *buf2 = NULL; BerValue *val; BerElement *ber; /* Calculate the BER container length * * SPKI := SEQUENCE { * SEQUENCE { * OID * Parameters * } * BITSTRING public key * } */ offset = 0; rc = 0; total = 0; parm_len = 0; id_len = 0; pub_len = 0; /* OID and parameters */ rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, prime->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, base->ulValueLen); offset += len; rc |= ber_encode_SEQUENCE(TRUE, NULL, &parm_len, NULL, offset); rc |= ber_encode_SEQUENCE(TRUE, NULL, &id_len, NULL, ber_idDHLen + parm_len); /* public key */ rc |= ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); rc = ber_flatten(ber, &val); pub_len = val->bv_len; ber_free(ber, 1); free(buf); rc |= ber_encode_SEQUENCE(TRUE, NULL, &total, NULL, id_len + pub_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_sequence failed with rc=0x%lx\n", __func__, rc); return rc; } if (length_only == TRUE) { *data_len = total; return rc; } buf = (CK_BYTE *) malloc(id_len + pub_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } /* Parameters */ offset = 0; rc = ber_encode_INTEGER(FALSE, &buf2, &len, prime->pValue, prime->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_INTEGER(FALSE, &buf2, &len, base->pValue, base->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &parm_len, buf, offset); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } /* OID and parameters */ memcpy(buf, ber_idDH, ber_idDHLen); memcpy(buf + ber_idDHLen, buf2, parm_len); free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &id_len, buf, ber_idDHLen + parm_len); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } free(buf); /* public key */ rc = ber_encode_INTEGER(FALSE, &buf, &len, value->pValue, value->ulValueLen); if (rc != CKR_OK) { TRACE_DEVEL("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } ber = ber_alloc_t(LBER_USE_DER); rc = ber_put_bitstring(ber, (char *)buf, len * 8, 0x03); rc = ber_flatten(ber, &val); free(buf); buf = (CK_BYTE *) malloc(id_len + val->bv_len); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } memcpy(buf, buf2, id_len); memcpy(buf + id_len, val->bv_val, val->bv_len); free(buf2); ber_free(ber, 1); /* outer sequence */ rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf, id_len + pub_len); if (rc != CKR_OK) { TRACE_DEVEL("%s der_encode_Seq failed with rc=0x%lx\n", __func__, rc); return rc; } free(buf); return rc; } CK_RV ber_decode_DHPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **prime, CK_ATTRIBUTE **base, CK_ATTRIBUTE **value) { CK_ATTRIBUTE *prime_attr = NULL; CK_ATTRIBUTE *base_attr = NULL; CK_ATTRIBUTE *value_attr = NULL; CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *val = NULL; CK_ULONG val_len; CK_BYTE *seq; CK_ULONG seq_len; CK_BYTE *p; CK_ULONG p_len; CK_BYTE *b; CK_ULONG b_len; CK_ULONG field_len, offset; CK_RV rc; UNUSED(data_len); // XXX can this parameter be removed ? rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } /* * Make sure we're dealing with an DH key. */ if (memcmp(algid, ber_idDH, ber_idDHLen) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } rc = ber_decode_SEQUENCE(param, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } rc = ber_decode_INTEGER(seq, &p, &p_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } offset = field_len; rc = ber_decode_INTEGER(seq + offset, &b, &b_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } // build prime attribute rc = build_attribute(CKA_PRIME, p, p_len, &prime_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build base attribute rc = build_attribute(CKA_BASE, b, b_len, &base_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } // build value attribute rc = build_attribute(CKA_VALUE, val, val_len, &value_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *prime = prime_attr; *base = base_attr; *value = value_attr; return CKR_OK; cleanup: if (prime_attr) free(prime_attr); if (base_attr) free(base_attr); if (value_attr) free(value_attr); return rc; } /** * An IBM Dilithium public key is given by: * * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 * NULL * BIT STRING (1 elem) * SEQUENCE (2 elem) * BIT STRING (256 bit) = 32 bytes * BIT STRING (13824 bit) = 1728 bytes */ CK_RV ber_encode_IBM_DilithiumPublicKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *t1) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL, *buf4 = NULL; CK_ULONG len, len4, offset, total, total_len; CK_RV rc; UNUSED(length_only); offset = 0; rc = 0; total_len = ber_AlgIdDilithiumLen; total = 0; /* Calculate storage for inner sequence */ rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, rho->ulValueLen); offset += len; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, t1->ulValueLen); offset += len; if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); return rc; } /* Allocate storage for inner sequence */ buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s Memory allocation failed\n", __func__); return CKR_HOST_MEMORY; } /** * SEQUENCE (2 elem) * BIT STRING -> rho * BIT STRING -> t */ offset = 0; rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, rho->pValue, rho->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, t1->pValue, t1->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_Int failed with rc=0x%lx\n", __func__, rc); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); goto error; } free(buf); buf = NULL; /* Calculate length of outer sequence */ rc = ber_encode_BIT_STRING(TRUE, NULL, &total, buf2, len, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_Oct_Str failed with rc=0x%lx\n", __func__, rc); goto error; } else { total_len += total; } /* Allocate storage for outer sequence and bit string */ buf3 = (CK_BYTE *) malloc(total_len); if (!buf3) { TRACE_ERROR("%s Memory allocation failed\n", __func__); rc = CKR_HOST_MEMORY; goto error; } /* * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 * NULL <- no parms for this oid */ total_len = 0; memcpy(buf3 + total_len, ber_AlgIdDilithium, ber_AlgIdDilithiumLen); total_len += ber_AlgIdDilithiumLen; /* * BIT STRING (1 elem) * SEQUENCE (2 elem) * BIT STRING -> rho * BIT STRING -> t1 */ rc = ber_encode_BIT_STRING(FALSE, &buf4, &len4, buf2, len, 0); if (rc != CKR_OK) { TRACE_ERROR("%s ber_encode_BIT_STRING failed with rc=0x%lx\n", __func__, rc); goto error; } memcpy(buf3 + total_len, buf4, len4); total_len += len4; free(buf4); buf4 = NULL; /** * SEQUENCE (2 elem) * SEQUENCE (2 elem) * OBJECT IDENTIFIER 1.3.6.1.4.1.2.267.1.6.5 * NULL -> no parms for this oid * BIT STRING (1 elem) * SEQUENCE (2 elem) * BIT STRING -> rho * BIT STRING -> t1 */ rc = ber_encode_SEQUENCE(FALSE, data, data_len, buf3, total_len); if (rc != CKR_OK) TRACE_ERROR("%s ber_encode_Seq failed with rc=0x%lx\n", __func__, rc); error: if (buf) free(buf); if (buf2) free(buf2); if (buf3) free(buf3); return rc; } CK_RV ber_decode_IBM_DilithiumPublicKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **rho_attr, CK_ATTRIBUTE **t1_attr) { CK_ATTRIBUTE *rho_attr_temp = NULL; CK_ATTRIBUTE *t1_attr_temp = NULL; CK_BYTE *algid_DilithiumBase = NULL; CK_BYTE *algid = NULL; CK_ULONG algid_len; CK_BYTE *param = NULL; CK_ULONG param_len; CK_BYTE *val = NULL; CK_ULONG val_len; CK_BYTE *seq; CK_ULONG seq_len; CK_BYTE *rho; CK_ULONG rho_len; CK_BYTE *t1; CK_ULONG t1_len; CK_ULONG field_len, offset, len; CK_RV rc; UNUSED(data_len); // XXX can this parameter be removed ? rc = ber_decode_SPKI(data, &algid, &algid_len, ¶m, ¶m_len, &val, &val_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SPKI failed\n"); return rc; } /* Make sure we're dealing with a Dilithium key */ rc = ber_decode_SEQUENCE((CK_BYTE *)ber_AlgIdDilithium, &algid_DilithiumBase, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } if (memcmp(algid, algid_DilithiumBase, len) != 0) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode sequence: * SEQUENCE (2 elem) * BIT STRING = rho * BIT STRING = t1 */ rc = ber_decode_SEQUENCE(val, &seq, &seq_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_SEQUENCE failed\n"); return rc; } /* Decode rho */ rc = ber_decode_BIT_STRING(seq, &rho, &rho_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } /* Decode t1 */ offset = field_len; rc = ber_decode_BIT_STRING(seq + offset, &t1, &t1_len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); return rc; } /* Build rho attribute */ rc = build_attribute(CKA_IBM_DILITHIUM_RHO, rho, rho_len, &rho_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } /* Build t1 attribute */ rc = build_attribute(CKA_IBM_DILITHIUM_T1, t1, t1_len, &t1_attr_temp); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute failed\n"); goto cleanup; } *rho_attr = rho_attr_temp; *t1_attr = t1_attr_temp; return CKR_OK; cleanup: if (rho_attr_temp) free(rho_attr_temp); if (t1_attr_temp) free(t1_attr_temp); return rc; } /** * An IBM Dilithium private key is given by: * * DilithiumPrivateKey ::= SEQUENCE { * version INTEGER, -- v0, reserved 0 * rho BIT STRING, -- nonce * key BIT STRING, -- key/seed/D * tr BIT STRING, -- PRF bytes ('CRH' in spec) * s1 BIT STRING, -- vector(L) * s2 BIT STRING, -- vector(K) * t0 BIT STRING -- low bits(vector L) * t1 [0] IMPLICIT OPTIONAL { * t1 BIT STRING -- high bits(vector L) -- see also public key * } * } */ CK_RV ber_encode_IBM_DilithiumPrivateKey(CK_BBOOL length_only, CK_BYTE **data, CK_ULONG *data_len, CK_ATTRIBUTE *rho, CK_ATTRIBUTE *seed, CK_ATTRIBUTE *tr, CK_ATTRIBUTE *s1, CK_ATTRIBUTE *s2, CK_ATTRIBUTE *t0, CK_ATTRIBUTE *t1) { CK_BYTE *buf = NULL, *buf2 = NULL, *buf3 = NULL; CK_ULONG len, len2, offset; CK_BYTE version[] = { 0 }; CK_RV rc; /* Calculate storage for sequence */ offset = 0; rc = 0; rc |= ber_encode_INTEGER(TRUE, NULL, &len, NULL, sizeof(version)); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, rho->ulValueLen, 0); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, seed->ulValueLen, 0); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, tr->ulValueLen, 0); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, s1->ulValueLen, 0); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, s2->ulValueLen, 0); offset += len; rc |= ber_encode_BIT_STRING(TRUE, NULL, &len, NULL, t0->ulValueLen, 0); offset += len; if (t1) { rc |= ber_encode_BIT_STRING(TRUE, NULL, &len2, NULL, t1->ulValueLen, 0); rc |= ber_encode_CHOICE(TRUE, 0, NULL, &len, NULL, len2); offset += len; } if (rc != CKR_OK) { TRACE_DEVEL("Calculate storage for sequence failed\n"); return CKR_FUNCTION_FAILED; } if (length_only == TRUE) { rc = ber_encode_SEQUENCE(TRUE, NULL, &len, NULL, offset); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_SEQUENCE failed\n"); return rc; } rc = ber_encode_PrivateKeyInfo(TRUE, NULL, data_len, NULL, ber_AlgIdDilithiumLen, NULL, len); if (rc != CKR_OK) { TRACE_DEVEL("ber_encode_PrivateKeyInfo failed\n"); return rc; } return rc; } /* Allocate storage for sequence */ buf = (CK_BYTE *) malloc(offset); if (!buf) { TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY)); return CKR_HOST_MEMORY; } offset = 0; rc = 0; /* Version */ rc = ber_encode_INTEGER(FALSE, &buf2, &len, version, sizeof(version)); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_INTEGER of version failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* rho */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, rho->pValue, rho->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of rho failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* seed */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, seed->pValue, seed->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of seed failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* tr */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, tr->pValue, tr->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of (tr) failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* s1 */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, s1->pValue, s1->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of (s1) failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* s2 */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, s2->pValue, s2->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of (s2) failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* t0 */ rc = ber_encode_BIT_STRING(FALSE, &buf2, &len, t0->pValue, t0->ulValueLen, 0); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_BIT_STRING of (t0) failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; /* (t1) Optional bit-string of public key */ if (t1 && t1->pValue) { rc = ber_encode_BIT_STRING(FALSE, &buf3, &len2, t1->pValue, t1->ulValueLen, 0); rc |= ber_encode_CHOICE(FALSE, 0, &buf2, &len, buf3, len2); if (rc != CKR_OK) { TRACE_ERROR("encoding of t1 value failed\n"); goto error; } memcpy(buf + offset, buf2, len); offset += len; free(buf2); buf2 = NULL; } /* Encode sequence */ rc = ber_encode_SEQUENCE(FALSE, &buf2, &len, buf, offset); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_SEQUENCE failed\n"); goto error; } rc = ber_encode_PrivateKeyInfo(FALSE, data, data_len, ber_AlgIdDilithium, ber_AlgIdDilithiumLen, buf2, len); if (rc != CKR_OK) { TRACE_ERROR("ber_encode_PrivateKeyInfo failed\n"); } error: if (buf3) free(buf3); if (buf2) free(buf2); if (buf) free(buf); return rc; } /** * decode an IBM Dilithium private key: * * DilithiumPrivateKey ::= SEQUENCE { * version INTEGER, -- v0, reserved 0 * rho BIT STRING, -- nonce * key BIT STRING, -- key/seed/D * tr BIT STRING, -- PRF bytes ('CRH' in spec) * s1 BIT STRING, -- vector(L) * s2 BIT STRING, -- vector(K) * t0 BIT STRING -- low bits(vector L) * t1 [0] IMPLICIT OPTIONAL { * t1 BIT STRING -- high bits(vector L) -- see also public key * } * } */ CK_RV ber_decode_IBM_DilithiumPrivateKey(CK_BYTE *data, CK_ULONG data_len, CK_ATTRIBUTE **rho, CK_ATTRIBUTE **seed, CK_ATTRIBUTE **tr, CK_ATTRIBUTE **s1, CK_ATTRIBUTE **s2, CK_ATTRIBUTE **t0, CK_ATTRIBUTE **t1) { CK_ATTRIBUTE *rho_attr = NULL, *seed_attr = NULL; CK_ATTRIBUTE *tr_attr = NULL, *s1_attr = NULL, *s2_attr = NULL; CK_ATTRIBUTE *t0_attr = NULL, *t1_attr = NULL; CK_BYTE *alg = NULL; CK_BYTE *dilithium_priv_key = NULL; CK_BYTE *buf = NULL; CK_BYTE *tmp = NULL; CK_ULONG offset, buf_len, field_len, len; CK_RV rc; /* Check if this is a Dilithium private key */ rc = ber_decode_PrivateKeyInfo(data, data_len, &alg, &len, &dilithium_priv_key); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_PrivateKeyInfo failed\n"); return rc; } if (memcmp(alg, ber_AlgIdDilithium, ber_AlgIdDilithiumLen) != 0) { // probably ought to use a different error TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); return CKR_FUNCTION_FAILED; } /* Decode private Dilithium key */ rc = ber_decode_SEQUENCE(dilithium_priv_key, &buf, &buf_len, &field_len); if (rc != CKR_OK) return rc; /* Now build the attributes */ offset = 0; /* Skip the version */ rc = ber_decode_INTEGER(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_INTEGER failed\n"); goto cleanup; } offset += field_len; /* rho */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (rho) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_RHO, tmp, len, &rho_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (rho) failed\n"); goto cleanup; } offset += field_len; } /* seed */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (seed) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_SEED, tmp, len, &seed_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (seed) failed\n"); goto cleanup; } offset += field_len; } /* tr */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (tr) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_TR, tmp, len, &tr_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (tr) failed\n"); goto cleanup; } offset += field_len; } /* s1 */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (s1) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_S1, tmp, len, &s1_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (s1) failed\n"); goto cleanup; } offset += field_len; } /* s2 */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (s2) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_S2, tmp, len, &s2_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (s2) failed\n"); goto cleanup; } offset += field_len; } /* t0 */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t0) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_T0, tmp, len, &t0_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (t0) failed\n"); goto cleanup; } offset += field_len; } /* t1 */ rc = ber_decode_BIT_STRING(buf + offset, &tmp, &len, &field_len); if (rc != CKR_OK) { TRACE_DEVEL("ber_decode_BIT_STRING of (t1) failed\n"); goto cleanup; } else { rc = build_attribute(CKA_IBM_DILITHIUM_T1, tmp, len, &t1_attr); if (rc != CKR_OK) { TRACE_DEVEL("build_attribute for (t1) failed\n"); goto cleanup; } offset += field_len; } /* Check if buffer big enough */ if (offset > buf_len) { TRACE_ERROR("%s\n", ock_err(ERR_FUNCTION_FAILED)); rc = CKR_FUNCTION_FAILED; goto cleanup; } *rho = rho_attr; *seed = seed_attr; *tr = tr_attr; *s1 = s1_attr; *s2 = s2_attr; *t0 = t0_attr; *t1 = t1_attr; return CKR_OK; cleanup: if (seed_attr) free(seed_attr); if (t1_attr) free(t1_attr); if (rho_attr) free(rho_attr); if (seed_attr) free(seed_attr); if (tr_attr) free(tr_attr); if (s1_attr) free(s1_attr); if (s2_attr) free(s2_attr); if (t0_attr) free(t0_attr); return rc; }