PROV: Add the beginning of a DER writing library
[openssl.git] / crypto / der_writer.c
1 /*
2  * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <stdlib.h>
11 #include <string.h>
12 #include "internal/cryptlib.h"
13 #include "internal/der.h"
14 #include "crypto/bn.h"
15
16 static int int_start_context(WPACKET *pkt, int tag)
17 {
18     if (tag < 0)
19         return 1;
20     if (!ossl_assert(tag <= 30))
21         return 0;
22     return WPACKET_start_sub_packet(pkt);
23 }
24
25 static int int_end_context(WPACKET *pkt, int tag)
26 {
27     if (tag < 0)
28         return 1;
29     if (!ossl_assert(tag <= 30))
30         return 0;
31     return WPACKET_close(pkt)
32         && WPACKET_put_bytes_u8(pkt, DER_C_CONTEXT | tag);
33 }
34
35 int DER_w_precompiled(WPACKET *pkt, int tag,
36                       const unsigned char *precompiled, size_t precompiled_n)
37 {
38     return int_start_context(pkt, tag)
39         && WPACKET_memcpy(pkt, precompiled, precompiled_n)
40         && int_end_context(pkt, tag);
41 }
42
43 int DER_w_boolean(WPACKET *pkt, int tag, int b)
44 {
45     return int_start_context(pkt, tag)
46         && WPACKET_start_sub_packet(pkt)
47         && (!b || WPACKET_put_bytes_u8(pkt, 0xFF))
48         && !WPACKET_close(pkt)
49         && !WPACKET_put_bytes_u8(pkt, DER_P_BOOLEAN)
50         && int_end_context(pkt, tag);
51 }
52
53 static int int_der_w_integer(WPACKET *pkt, int tag,
54                              int (*put_bytes)(WPACKET *pkt, const void *v,
55                                               unsigned int *top_byte),
56                              const void *v)
57 {
58     unsigned int top_byte = 0;
59
60     return int_start_context(pkt, tag)
61         && WPACKET_start_sub_packet(pkt)
62         && put_bytes(pkt, v, &top_byte)
63         && ((top_byte & 0x80) == 0 || WPACKET_put_bytes_u8(pkt, 0))
64         && WPACKET_close(pkt)
65         && WPACKET_put_bytes_u8(pkt, DER_P_INTEGER)
66         && int_end_context(pkt, tag);
67 }
68
69 static int int_put_bytes_ulong(WPACKET *pkt, const void *v,
70                                unsigned int *top_byte)
71 {
72     const unsigned long *value = v;
73     unsigned long tmp = *value;
74     size_t n = 0;
75
76     while (tmp != 0) {
77         n++;
78         *top_byte = (tmp & 0xFF);
79         tmp >>= 8;
80     }
81     if (n == 0)
82         n = 1;
83
84     return WPACKET_put_bytes__(pkt, *value, n);
85 }
86
87 /* For integers, we only support unsigned values for now */
88 int DER_w_ulong(WPACKET *pkt, int tag, unsigned long v)
89 {
90     return int_der_w_integer(pkt, tag, int_put_bytes_ulong, &v);
91 }
92
93 static int int_put_bytes_bn(WPACKET *pkt, const void *v,
94                             unsigned int *top_byte)
95 {
96     unsigned char *p = NULL;
97     size_t n = BN_num_bytes(v);
98
99     /* The BIGNUM limbs are in LE order */
100     *top_byte =
101         ((bn_get_words(v) [(n - 1) / BN_BYTES]) >> (8 * ((n - 1) % BN_BYTES)))
102         & 0xFF;
103
104     if (!WPACKET_allocate_bytes(pkt, n, &p))
105         return 0;
106     if (p != NULL)
107         BN_bn2bin(v, p);
108     return 1;
109 }
110
111 int DER_w_bn(WPACKET *pkt, int tag, const BIGNUM *v)
112 {
113     if (v == NULL || BN_is_negative(v))
114         return 0;
115     if (BN_is_zero(v))
116         return DER_w_ulong(pkt, tag, 0);
117
118     return int_der_w_integer(pkt, tag, int_put_bytes_bn, v);
119 }
120
121 int DER_w_null(WPACKET *pkt, int tag)
122 {
123     return int_start_context(pkt, tag)
124         && WPACKET_start_sub_packet(pkt)
125         && WPACKET_close(pkt)
126         && WPACKET_put_bytes_u8(pkt, DER_P_NULL)
127         && int_end_context(pkt, tag);
128 }
129
130 /* Constructed things need a start and an end */
131 int DER_w_begin_sequence(WPACKET *pkt, int tag)
132 {
133     return int_start_context(pkt, tag)
134         && WPACKET_start_sub_packet(pkt);
135 }
136
137 int DER_w_end_sequence(WPACKET *pkt, int tag)
138 {
139     return WPACKET_close(pkt)
140         && WPACKET_put_bytes_u8(pkt, DER_F_CONSTRUCTED | DER_P_SEQUENCE)
141         && int_end_context(pkt, tag);
142 }