summaryrefslogtreecommitdiffstats
path: root/include/iprt/crypto/pem.h
blob: 0fe1aefd9e969e2f4c01325ea39a3f379bd6d70f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/** @file
 * IPRT - Crypto - PEM-file Reader & Writer.
 */

/*
 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
 *
 * This file is part of VirtualBox base platform packages, as
 * available from https://www.virtualbox.org.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation, in version 3 of the
 * License.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses>.
 *
 * The contents of this file may alternatively be used under the terms
 * of the Common Development and Distribution License Version 1.0
 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
 * in the VirtualBox distribution, in which case the provisions of the
 * CDDL are applicable instead of those of the GPL.
 *
 * You may elect to license modified versions of this file under the
 * terms and conditions of either the GPL or the CDDL or both.
 *
 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
 */

#ifndef IPRT_INCLUDED_crypto_pem_h
#define IPRT_INCLUDED_crypto_pem_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/types.h>
#include <iprt/asn1.h>   /* PRTASN1CORE */
#include <iprt/string.h> /* PFNRTSTROUTPUT */


RT_C_DECLS_BEGIN

/** @defgroup grp_rt_spc  RTCrPem - PEM-file Reader & Writer
 * @ingroup grp_rt_crypto
 * @{
 */


/**
 * One PEM marker word (use RT_STR_TUPLE to initialize).
 */
typedef struct RTCRPEMMARKERWORD
{
    /** The word string. */
    const char         *pszWord;
    /** The length. */
    uint32_t            cchWord;
} RTCRPEMMARKERWORD;
/** Pointer to a const marker word. */
typedef RTCRPEMMARKERWORD const *PCRTCRPEMMARKERWORD;


/**
 * A PEM marker.
 *
 * This is an array of words with lengths, optimized for avoid unnecessary
 * strlen() while searching the file content.  It is ASSUMED that all PEM
 * section markers starts with either 'BEGIN' or 'END', followed by the words
 * in the this structure.
 */
typedef struct RTCRPEMMARKER
{
    /** Pointer to an array of marker words. */
    PCRTCRPEMMARKERWORD paWords;
    /** Number of works in the array papszWords points to. */
    uint32_t            cWords;
} RTCRPEMMARKER;
/** Pointer to a const PEM marker. */
typedef RTCRPEMMARKER const *PCRTCRPEMMARKER;


/**
 * A PEM field.
 */
typedef struct RTCRPEMFIELD
{
    /** Pointer to the next field. */
    struct RTCRPEMFIELD const *pNext;
    /** The field value. */
    char const         *pszValue;
    /** The field value length. */
    size_t              cchValue;
    /** The field name length. */
    size_t              cchName;
    /** The field name. */
    RT_FLEXIBLE_ARRAY_EXTENSION
    char                szName[RT_FLEXIBLE_ARRAY];
} RTCRPEMFIELD;
/** Pointer to a PEM field. */
typedef RTCRPEMFIELD *PRTCRPEMFIELD;
/** Pointer to a const PEM field. */
typedef RTCRPEMFIELD const *PCRTCRPEMFIELD;


/**
 * A PEM section.
 *
 * The API works on linked lists of these.
 */
typedef struct RTCRPEMSECTION
{
    /** Pointer to the next file section. */
    struct RTCRPEMSECTION const *pNext;
    /** The marker for this section.  NULL if binary file. */
    PCRTCRPEMMARKER     pMarker;
    /** Pointer to the binary data. */
    uint8_t            *pbData;
    /** The size of the binary data. */
    size_t              cbData;
    /** List of fields, NULL if none. */
    PCRTCRPEMFIELD      pFieldHead;
    /** Set if RTCRPEMREADFILE_F_SENSITIVE was specified. */
    bool                fSensitive;
} RTCRPEMSECTION;
/** Pointer to a PEM section. */
typedef RTCRPEMSECTION *PRTCRPEMSECTION;
/** Pointer to a const PEM section. */
typedef RTCRPEMSECTION const *PCRTCRPEMSECTION;


/**
 * Frees sections returned by RTCrPemReadFile and RTCrPemParseContent.
 * @returns IPRT status code.
 * @param   pSectionHead        The first section.
 */
RTDECL(int) RTCrPemFreeSections(PCRTCRPEMSECTION pSectionHead);

/**
 * Parses the given data and returns a list of binary sections.
 *
 * If the file isn't an ASCII file or if no markers were found, the entire file
 * content is returned as one single section (with pMarker = NULL).
 *
 * @returns IPRT status code.
 * @retval  VINF_EOF if the file is empty.  The @a ppSectionHead value will be
 *          NULL.
 * @retval  VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM
 *          is specified.  The @a ppSectionHead value will be NULL.
 *
 * @param   pvContent       The content bytes to parse.
 * @param   cbContent       The number of content bytes.
 * @param   fFlags          RTCRPEMREADFILE_F_XXX.
 * @param   paMarkers       Array of one or more section markers to look for.
 * @param   cMarkers        Number of markers in the array.
 * @param   ppSectionHead   Where to return the head of the section list.  Call
 *                          RTCrPemFreeSections to free.
 * @param   pErrInfo        Where to return extend error info. Optional.
 */
RTDECL(int) RTCrPemParseContent(void const *pvContent, size_t cbContent, uint32_t fFlags,
                                PCRTCRPEMMARKER paMarkers, size_t cMarkers, PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo);

/**
 * Reads the content of the given file and returns a list of binary sections
 * found in the file.
 *
 * If the file isn't an ASCII file or if no markers were found, the entire file
 * content is returned as one single section (with pMarker = NULL).
 *
 * @returns IPRT status code.
 * @retval  VINF_EOF if the file is empty.  The @a ppSectionHead value will be
 *          NULL.
 * @retval  VWRN_NOT_FOUND no section was found and RTCRPEMREADFILE_F_ONLY_PEM
 *          is specified.  The @a ppSectionHead value will be NULL.
 *
 * @param   pszFilename     The path to the file to read.
 * @param   fFlags          RTCRPEMREADFILE_F_XXX.
 * @param   paMarkers       Array of one or more section markers to look for.
 * @param   cMarkers        Number of markers in the array.
 * @param   ppSectionHead   Where to return the head of the section list. Call
 *                          RTCrPemFreeSections to free.
 * @param   pErrInfo        Where to return extend error info. Optional.
 */
RTDECL(int) RTCrPemReadFile(const char *pszFilename, uint32_t fFlags, PCRTCRPEMMARKER paMarkers, size_t cMarkers,
                            PCRTCRPEMSECTION *ppSectionHead, PRTERRINFO pErrInfo);
/** @name RTCRPEMREADFILE_F_XXX - Flags for RTCrPemReadFile and
 *        RTCrPemParseContent.
 * @{ */
/** Continue on encoding error. */
#define RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR    RT_BIT(0)
/** Only PEM sections, no binary fallback. */
#define RTCRPEMREADFILE_F_ONLY_PEM                      RT_BIT(1)
/** Sensitive data, use the safer allocator. */
#define RTCRPEMREADFILE_F_SENSITIVE                     RT_BIT(2)
/** Valid flags. */
#define RTCRPEMREADFILE_F_VALID_MASK                    UINT32_C(0x00000007)
/** @} */

/**
 * Finds the beginning of first PEM section using the specified markers.
 *
 * This will not look any further than the first section.  Nor will it check for
 * binaries.
 *
 * @returns Pointer to the "-----BEGIN XXXX" sequence on success.
 *          NULL if not found.
 * @param   pvContent       The content bytes to parse.
 * @param   cbContent       The number of content bytes.
 * @param   paMarkers       Array of one or more section markers to look for.
 * @param   cMarkers        Number of markers in the array.
 */
RTDECL(const char *) RTCrPemFindFirstSectionInContent(void const *pvContent, size_t cbContent,
                                                      PCRTCRPEMMARKER paMarkers, size_t cMarkers);


/**
 * PEM formatter for a binary data blob.
 *
 * @returns Number of output bytes (sum of @a pfnOutput return values).
 * @param   pfnOutput       The output callback function.
 * @param   pvUser          The user argument to the output callback.
 * @param   pvContent       The binary blob to output.
 * @param   cbContent       Size of the binary blob.
 * @param   pszMarker       The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or
 *                          similar.
 * @sa      RTCrPemWriteAsn1, RTCrPemWriteAsn1ToVfsFile,
 *          RTCrPemWriteAsn1ToVfsFile
 */
RTDECL(size_t) RTCrPemWriteBlob(PFNRTSTROUTPUT pfnOutput, void *pvUser,
                                const void *pvContent, size_t cbContent, const char *pszMarker);

RTDECL(ssize_t) RTCrPemWriteBlobToVfsIoStrm(RTVFSIOSTREAM hVfsIos, const void *pvContent, size_t cbContent, const char *pszMarker);
RTDECL(ssize_t) RTCrPemWriteBlobToVfsFile(RTVFSFILE hVfsFile, const void *pvContent, size_t cbContent, const char *pszMarker);

/**
 * PEM formatter for a generic ASN.1 structure.
 *
 * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on
 * @a pRoot.  Uses DER encoding.
 *
 * @returns Number of outputted chars (sum of @a pfnOutput return values),
 *          negative values are error status codes from the ASN.1 encoding.
 * @param   pfnOutput       The output callback function.
 * @param   pvUser          The user argument to the output callback.
 * @param   fFlags          Reserved, MBZ.
 * @param   pRoot           The root of the ASN.1 to encode and format as PEM.
 * @param   pszMarker       The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or
 *                          similar.
 * @param   pErrInfo        For encoding errors. Optional.
 * @sa      RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1ToVfsFile,
 *          RTCrPemWriteBlob
 */
RTDECL(ssize_t) RTCrPemWriteAsn1(PFNRTSTROUTPUT pfnOutput, void *pvUser, PRTASN1CORE pRoot,
                                 uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo);

/**
 * PEM formatter for a generic ASN.1 structure and output it to @a hVfsIos.
 *
 * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on
 * @a pRoot.  Uses DER encoding.
 *
 * @returns Number of chars written, negative values are error status codes from
 *          the ASN.1 encoding or from RTVfsIoStrmWrite().
 * @param   hVfsIos         Handle to the I/O stream to write it to.
 * @param   fFlags          Reserved, MBZ.
 * @param   pRoot           The root of the ASN.1 to encode and format as PEM.
 * @param   pszMarker       The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or
 *                          similar.
 * @param   pErrInfo        For encoding errors. Optional.
 * @sa      RTCrPemWriteAsn1ToVfsFile, RTCrPemWriteAsn1, RTCrPemWriteBlob
 */
RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsIoStrm(RTVFSIOSTREAM hVfsIos, PRTASN1CORE pRoot,
                                            uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo);

/**
 * PEM formatter for a generic ASN.1 structure and output it to @a hVfsFile.
 *
 * This will call both RTAsn1EncodePrepare() and RTAsn1EncodeWrite() on
 * @a pRoot.  Uses DER encoding.
 *
 * @returns Number of chars written, negative values are error status codes from
 *          the ASN.1 encoding or from RTVfsIoStrmWrite().
 * @param   hVfsFile        Handle to the file to write it to.
 * @param   fFlags          Reserved, MBZ.
 * @param   pRoot           The root of the ASN.1 to encode and format as PEM.
 * @param   pszMarker       The PEM marker, .e.g "PRIVATE KEY", "CERTIFICATE" or
 *                          similar.
 * @param   pErrInfo        For encoding errors. Optional.
 * @sa      RTCrPemWriteAsn1ToVfsIoStrm, RTCrPemWriteAsn1, RTCrPemWriteBlob
 */
RTDECL(ssize_t) RTCrPemWriteAsn1ToVfsFile(RTVFSFILE hVfsFile, PRTASN1CORE pRoot,
                                          uint32_t fFlags, const char *pszMarker, PRTERRINFO pErrInfo);

/** @} */

RT_C_DECLS_END

#endif /* !IPRT_INCLUDED_crypto_pem_h */