diff --git a/crypto/Makefile b/crypto/Makefile index 627814136..5578ae726 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -125,6 +125,7 @@ SRCS += zkp_bip340.c SRCS += cardano.c SRCS += tls_prf.c SRCS += hash_to_curve.c +SRCS += buffer.c der.c OBJS = $(SRCS:.c=.o) OBJS += secp256k1-zkp.o diff --git a/crypto/buffer.c b/crypto/buffer.c new file mode 100644 index 000000000..829aad1d2 --- /dev/null +++ b/crypto/buffer.c @@ -0,0 +1,122 @@ +/** + * Copyright (c) 2023 Trezor Company s.r.o. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include + +#include "buffer.h" + +void buffer_reader_init(BUFFER_READER *reader, const uint8_t *data, + size_t size) { + reader->data = data; + reader->size = size; + reader->pos = 0; +} + +void buffer_writer_init(BUFFER_WRITER *writer, uint8_t *data, size_t size) { + writer->data = data; + writer->size = size; + writer->pos = 0; +} + +size_t buffer_remaining(BUFFER_READER *buf) { + if ((buf->data == NULL) || (buf->pos > buf->size)) { + return 0; + } + + return buf->size - buf->pos; +} + +bool buffer_peek(const BUFFER_READER *buf, uint8_t *byte) { + if ((buf->data == NULL) || (buf->pos >= buf->size)) { + return false; + } + + *byte = buf->data[buf->pos]; + return true; +} + +bool buffer_get(BUFFER_READER *buf, uint8_t *byte) { + if (!buffer_peek(buf, byte)) { + return false; + } + + buf->pos += 1; + return true; +} + +bool buffer_read_buffer(BUFFER_READER *src, BUFFER_READER *dest, size_t size) { + if ((src->data == NULL) || (src->pos + size > src->size)) { + return false; + } + + buffer_reader_init(dest, &src->data[src->pos], size); + src->pos += size; + return true; +} + +void buffer_lstrip(BUFFER_READER *buf, uint8_t byte) { + if (buf->data == NULL) { + return; + } + + while ((buf->pos < buf->size) && (buf->data[buf->pos] == byte)) { + buf->pos += 1; + } + return; +} + +bool buffer_put(BUFFER_WRITER *writer, uint8_t byte) { + if ((writer->data == NULL) || (writer->pos >= writer->size)) { + return false; + } + + writer->data[writer->pos] = byte; + writer->pos += 1; + return true; +} + +bool buffer_write_array(BUFFER_WRITER *writer, const uint8_t *src, + size_t size) { + if ((writer->data == NULL) || (writer->pos + size > writer->size)) { + return false; + } + + memcpy(&writer->data[writer->pos], src, size); + writer->pos += size; + return true; +} + +bool buffer_write_buffer(BUFFER_WRITER *dest, BUFFER_READER *src) { + if ((src->data == NULL) || (src->pos > src->size)) { + return false; + } + + if (!buffer_write_array(dest, &src->data[src->pos], src->size - src->pos)) { + return false; + } + + src->pos = src->size; + return true; +} + +size_t buffer_written_size(BUFFER_WRITER *writer) { return writer->pos; } diff --git a/crypto/buffer.h b/crypto/buffer.h new file mode 100644 index 000000000..4c2f4e608 --- /dev/null +++ b/crypto/buffer.h @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2023 Trezor Company s.r.o. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __BUFFER_H +#define __BUFFER_H + +#include +#include +#include + +#include "options.h" + +// Buffer reader struct, wraps a pointer to const data. +typedef struct { + const uint8_t *data; + size_t size; + size_t pos; +} BUFFER_READER; + +// Buffer writer struct, wraps a pointer to non-const data. +typedef struct { + uint8_t *data; + size_t size; + size_t pos; +} BUFFER_WRITER; + +void buffer_reader_init(BUFFER_READER *buf, const uint8_t *data, size_t size); +void buffer_writer_init(BUFFER_WRITER *buf, uint8_t *data, size_t size); +size_t __wur buffer_remaining(BUFFER_READER *buf); +bool __wur buffer_peek(const BUFFER_READER *buf, uint8_t *byte); +bool __wur buffer_get(BUFFER_READER *buf, uint8_t *byte); +bool __wur buffer_read_buffer(BUFFER_READER *src, BUFFER_READER *dest, + size_t size); +void buffer_lstrip(BUFFER_READER *buf, uint8_t byte); +bool __wur buffer_put(BUFFER_WRITER *writer, uint8_t byte); +bool __wur buffer_write_array(BUFFER_WRITER *writer, const uint8_t *src, + size_t size); +bool __wur buffer_write_buffer(BUFFER_WRITER *dest, BUFFER_READER *src); +size_t __wur buffer_written_size(BUFFER_WRITER *writer); + +#endif // __BUFFER_H diff --git a/crypto/der.c b/crypto/der.c new file mode 100644 index 000000000..d6a585556 --- /dev/null +++ b/crypto/der.c @@ -0,0 +1,101 @@ +/** + * Copyright (c) 2023 Trezor Company s.r.o. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "der.h" + +bool der_read_length(BUFFER_READER *buf, size_t *len) { + // Read the initial octet. + uint8_t init = 0; + if (!buffer_get(buf, &init)) { + return false; + } + + if (init < 0x80) { + // Short form. Encodes length in initial octet. + *len = init; + return true; + } + + if (init == 0x80 || init == 0xFF) { + // Indefinite length or RFU. + return false; + } + + // Long form. + uint8_t byte = 0; + if (!buffer_peek(buf, &byte) || byte == 0) { + // Encoding is not the shortest possible. + return false; + } + + if ((init & 0x7F) > sizeof(*len)) { + // Length overflow. + return false; + } + + *len = 0; + for (int i = 0; i < (init & 0x7F); ++i) { + if (!buffer_get(buf, &byte)) { + return false; + } + *len = (*len << 8) + byte; + } + + if (*len < 0x80) { + // Encoding is not the shortest possible. + return false; + } + + return true; +} + +bool der_write_length(BUFFER_WRITER *buf, size_t len) { + if (len < 0x80) { + // Short form. Encodes length in initial octet. + return buffer_put(buf, len); + } + + // Long form. + uint8_t encoding[sizeof(len) + 1] = {0}; + size_t pos = sizeof(encoding) - 1; + while (len != 0) { + encoding[pos] = len & 0xff; + len >>= 8; + pos -= 1; + } + encoding[pos] = 0x80 | (sizeof(encoding) - 1 - pos); + return buffer_write_array(buf, &encoding[pos], sizeof(encoding) - pos); +} + +bool der_read_item(BUFFER_READER *buf, DER_ITEM *item) { + if (!buffer_get(buf, &item->id) || ((item->id & 0x1f) == 0x1f)) { + // Multi-byte identifiers not supported. + return false; + } + + size_t len = 0; + if (!der_read_length(buf, &len)) { + return false; + } + + return buffer_read_buffer(buf, &item->cont, len); +} diff --git a/crypto/der.h b/crypto/der.h new file mode 100644 index 000000000..c55bdefd8 --- /dev/null +++ b/crypto/der.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2023 Trezor Company s.r.o. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT HMAC_SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef __DER_H +#define __DER_H + +#include +#include +#include + +#include "buffer.h" +#include "options.h" + +#define DER_SEQUENCE 0x30 +#define DER_INTEGER 0x02 + +typedef struct { + uint8_t id; + BUFFER_READER cont; +} DER_ITEM; + +bool __wur der_read_length(BUFFER_READER *buf, size_t *len); +bool __wur der_write_length(BUFFER_WRITER *buf, size_t len); +bool __wur der_read_item(BUFFER_READER *buf, DER_ITEM *item); + +#endif // __DER_H diff --git a/crypto/options.h b/crypto/options.h index aacd9e728..94f5c3ba6 100644 --- a/crypto/options.h +++ b/crypto/options.h @@ -91,4 +91,9 @@ #define CONFIDENTIAL #endif +// add way to mark functions whose return value should always be checked +#ifndef __wur +#define __wur __attribute__((warn_unused_result)) +#endif + #endif