1 /*
2  * Copyright (C) 2015 Red Hat, Inc.
3  *
4  * Author: Nikos Mavrogiannopoulos
5  *
6  * This file is part of GnuTLS.
7  *
8  * The GnuTLS is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program.  If not, see <https://www.gnu.org/licenses/>
20  *
21  */
22 
23 /* Functions that relate on PKCS7 attribute setting.
24  */
25 
26 #include "gnutls_int.h"
27 
28 #include <datum.h>
29 #include <global.h>
30 #include "errors.h"
31 #include <common.h>
32 #include <x509_b64.h>
33 #include <gnutls/abstract.h>
34 #include <gnutls/pkcs7.h>
35 
36 /**
37  * gnutls_pkcs7_add_attr:
38  * @list: A list of existing attributes or pointer to %NULL for the first one
39  * @oid: the OID of the attribute to be set
40  * @data: the raw (DER-encoded) data of the attribute to be set
41  * @flags: zero or %GNUTLS_PKCS7_ATTR_ENCODE_OCTET_STRING
42  *
43  * This function will set a PKCS #7 attribute in the provided list.
44  * If this function fails, the previous list would be deallocated.
45  *
46  * Note that any attributes set with this function must either be
47  * DER or BER encoded, unless a special flag is present.
48  *
49  * Returns: On success, the new list head, otherwise %NULL.
50  *
51  * Since: 3.4.2
52  **/
53 int
gnutls_pkcs7_add_attr(gnutls_pkcs7_attrs_t * list,const char * oid,gnutls_datum_t * data,unsigned flags)54 gnutls_pkcs7_add_attr(gnutls_pkcs7_attrs_t * list, const char *oid,
55 		      gnutls_datum_t * data, unsigned flags)
56 {
57 	int ret;
58 	gnutls_pkcs7_attrs_st *r;
59 
60 	r = gnutls_calloc(1, sizeof(gnutls_pkcs7_attrs_st));
61 	if (r == NULL)
62 		goto fail;
63 
64 	if (flags & GNUTLS_PKCS7_ATTR_ENCODE_OCTET_STRING) {
65 		ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING,
66 						 data->data, data->size,
67 						 &r->data);
68 	} else {
69 		ret = _gnutls_set_datum(&r->data, data->data, data->size);
70 	}
71 	if (ret < 0)
72 		goto fail;
73 
74 	r->oid = gnutls_strdup(oid);
75 	if (r->oid == NULL)
76 		goto fail;
77 
78 	r->next = *list;
79 	*list = r;
80 
81 	return 0;
82  fail:
83 	if (r) {
84 		gnutls_free(r->data.data);
85 		gnutls_free(r);
86 	}
87 	gnutls_pkcs7_attrs_deinit(*list);
88 	return GNUTLS_E_MEMORY_ERROR;
89 
90 }
91 
92 /**
93  * gnutls_pkcs7_get_attr:
94  * @list: A list of existing attributes or %NULL for the first one
95  * @idx: the index of the attribute to get
96  * @oid: the OID of the attribute (read-only)
97  * @data: the raw data of the attribute
98  * @flags: zero or %GNUTLS_PKCS7_ATTR_ENCODE_OCTET_STRING
99  *
100  * This function will get a PKCS #7 attribute from the provided list.
101  * The OID is a constant string, but data will be allocated and must be
102  * deinitialized by the caller.
103  *
104  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
105  *   negative error value. %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned
106  *   if there are no data in the current index.
107  *
108  * Since: 3.4.2
109  **/
110 int
gnutls_pkcs7_get_attr(gnutls_pkcs7_attrs_t list,unsigned idx,char ** oid,gnutls_datum_t * data,unsigned flags)111 gnutls_pkcs7_get_attr(gnutls_pkcs7_attrs_t list, unsigned idx, char **oid,
112 		      gnutls_datum_t * data, unsigned flags)
113 {
114 	unsigned i;
115 	gnutls_pkcs7_attrs_st *p = list;
116 	int ret;
117 
118 	for (i = 0; i < idx; i++) {
119 		p = p->next;
120 		if (p == NULL)
121 			break;
122 	}
123 
124 	if (p == NULL)
125 		return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
126 
127 	*oid = p->oid;
128 
129 	if (flags & GNUTLS_PKCS7_ATTR_ENCODE_OCTET_STRING) {
130 		ret = _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING,
131 						 p->data.data, p->data.size,
132 						 data, 1);
133 	} else {
134 		ret = _gnutls_set_datum(data, p->data.data, p->data.size);
135 	}
136 	if (ret < 0)
137 		return gnutls_assert_val(ret);
138 
139 	return 0;
140 }
141 
142 /**
143  * gnutls_pkcs7_attrs_deinit:
144  * @list: A list of existing attributes
145  *
146  * This function will clear a PKCS #7 attribute list.
147  *
148  * Since: 3.4.2
149  **/
gnutls_pkcs7_attrs_deinit(gnutls_pkcs7_attrs_t list)150 void gnutls_pkcs7_attrs_deinit(gnutls_pkcs7_attrs_t list)
151 {
152 	gnutls_pkcs7_attrs_st *r = list, *next;
153 
154 	while (r) {
155 		next = r->next;
156 
157 		gnutls_free(r->data.data);
158 		gnutls_free(r->oid);
159 		gnutls_free(r);
160 		r = next;
161 	}
162 }
163