Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / contrib / sslinfo / sslinfo.c
blob8482cfab9d3b25f4cec7090dc6891e2ca4a1f210
1 /*
2 * module for PostgreSQL to access client SSL certificate information
4 * Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD
5 * This file is distributed under BSD-style license.
7 * $PostgreSQL$
8 */
10 #include "postgres.h"
11 #include "fmgr.h"
12 #include "utils/numeric.h"
13 #include "libpq/libpq-be.h"
14 #include "miscadmin.h"
15 #include "utils/builtins.h"
16 #include "mb/pg_wchar.h"
18 #include <openssl/x509.h>
19 #include <openssl/asn1.h>
22 PG_MODULE_MAGIC;
25 Datum ssl_is_used(PG_FUNCTION_ARGS);
26 Datum ssl_client_cert_present(PG_FUNCTION_ARGS);
27 Datum ssl_client_serial(PG_FUNCTION_ARGS);
28 Datum ssl_client_dn_field(PG_FUNCTION_ARGS);
29 Datum ssl_issuer_field(PG_FUNCTION_ARGS);
30 Datum ssl_client_dn(PG_FUNCTION_ARGS);
31 Datum ssl_issuer_dn(PG_FUNCTION_ARGS);
32 Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
33 Datum X509_NAME_to_text(X509_NAME *name);
34 Datum ASN1_STRING_to_text(ASN1_STRING *str);
38 * Indicates whether current session uses SSL
40 * Function has no arguments. Returns bool. True if current session
41 * is SSL session and false if it is local or non-ssl session.
43 PG_FUNCTION_INFO_V1(ssl_is_used);
44 Datum
45 ssl_is_used(PG_FUNCTION_ARGS)
47 PG_RETURN_BOOL(MyProcPort->ssl != NULL);
52 * Indicates whether current client have provided a certificate
54 * Function has no arguments. Returns bool. True if current session
55 * is SSL session and client certificate is verified, otherwise false.
57 PG_FUNCTION_INFO_V1(ssl_client_cert_present);
58 Datum
59 ssl_client_cert_present(PG_FUNCTION_ARGS)
61 PG_RETURN_BOOL(MyProcPort->peer != NULL);
66 * Returns serial number of certificate used to establish current
67 * session
69 * Function has no arguments. It returns the certificate serial
70 * number as numeric or null if current session doesn't use SSL or if
71 * SSL connection is established without sending client certificate.
73 PG_FUNCTION_INFO_V1(ssl_client_serial);
74 Datum
75 ssl_client_serial(PG_FUNCTION_ARGS)
77 Datum result;
78 Port *port = MyProcPort;
79 X509 *peer = port->peer;
80 ASN1_INTEGER *serial = NULL;
81 BIGNUM *b;
82 char *decimal;
84 if (!peer)
85 PG_RETURN_NULL();
86 serial = X509_get_serialNumber(peer);
87 b = ASN1_INTEGER_to_BN(serial, NULL);
88 decimal = BN_bn2dec(b);
90 BN_free(b);
91 result = DirectFunctionCall3(numeric_in,
92 CStringGetDatum(decimal),
93 ObjectIdGetDatum(0),
94 Int32GetDatum(-1));
95 OPENSSL_free(decimal);
96 return result;
101 * Converts OpenSSL ASN1_STRING structure into text
103 * Converts ASN1_STRING into text, converting all the characters into
104 * current database encoding if possible. Any invalid characters are
105 * replaced by question marks.
107 * Parameter: str - OpenSSL ASN1_STRING structure. Memory managment
108 * of this structure is responsibility of caller.
110 * Returns Datum, which can be directly returned from a C language SQL
111 * function.
113 Datum
114 ASN1_STRING_to_text(ASN1_STRING *str)
116 BIO *membuf;
117 size_t size;
118 char nullterm;
119 char *sp;
120 char *dp;
121 text *result;
123 membuf = BIO_new(BIO_s_mem());
124 (void) BIO_set_close(membuf, BIO_CLOSE);
125 ASN1_STRING_print_ex(membuf, str,
126 ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
127 | ASN1_STRFLGS_UTF8_CONVERT));
128 /* ensure null termination of the BIO's content */
129 nullterm = '\0';
130 BIO_write(membuf, &nullterm, 1);
131 size = BIO_get_mem_data(membuf, &sp);
132 dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
133 size - 1,
134 PG_UTF8,
135 GetDatabaseEncoding());
136 result = cstring_to_text(dp);
137 if (dp != sp)
138 pfree(dp);
139 BIO_free(membuf);
141 PG_RETURN_TEXT_P(result);
146 * Returns specified field of specified X509_NAME structure
148 * Common part of ssl_client_dn and ssl_issuer_dn functions.
150 * Parameter: X509_NAME *name - either subject or issuer of certificate
151 * Parameter: text fieldName - field name string like 'CN' or commonName
152 * to be looked up in the OpenSSL ASN1 OID database
154 * Returns result of ASN1_STRING_to_text applied to appropriate
155 * part of name
157 Datum
158 X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
160 char *string_fieldname;
161 int nid,
162 index;
163 ASN1_STRING *data;
165 string_fieldname = text_to_cstring(fieldName);
166 nid = OBJ_txt2nid(string_fieldname);
167 if (nid == NID_undef)
168 ereport(ERROR,
169 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
170 errmsg("invalid X.509 field name: \"%s\"",
171 string_fieldname)));
172 pfree(string_fieldname);
173 index = X509_NAME_get_index_by_NID(name, nid, -1);
174 if (index < 0)
175 return (Datum) 0;
176 data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
177 return ASN1_STRING_to_text(data);
182 * Returns specified field of client certificate distinguished name
184 * Receives field name (like 'commonName' and 'emailAddress') and
185 * returns appropriate part of certificate subject converted into
186 * database encoding.
188 * Parameter: fieldname text - will be looked up in OpenSSL object
189 * identifier database
191 * Returns text string with appropriate value.
193 * Throws an error if argument cannot be converted into ASN1 OID by
194 * OpenSSL. Returns null if no client certificate is present, or if
195 * there is no field with such name in the certificate.
197 PG_FUNCTION_INFO_V1(ssl_client_dn_field);
198 Datum
199 ssl_client_dn_field(PG_FUNCTION_ARGS)
201 text *fieldname = PG_GETARG_TEXT_P(0);
202 Datum result;
204 if (!(MyProcPort->peer))
205 PG_RETURN_NULL();
207 result = X509_NAME_field_to_text(X509_get_subject_name(MyProcPort->peer), fieldname);
209 if (!result)
210 PG_RETURN_NULL();
211 else
212 return result;
217 * Returns specified field of client certificate issuer name
219 * Receives field name (like 'commonName' and 'emailAddress') and
220 * returns appropriate part of certificate subject converted into
221 * database encoding.
223 * Parameter: fieldname text - would be looked up in OpenSSL object
224 * identifier database
226 * Returns text string with appropriate value.
228 * Throws an error if argument cannot be converted into ASN1 OID by
229 * OpenSSL. Returns null if no client certificate is present, or if
230 * there is no field with such name in the certificate.
232 PG_FUNCTION_INFO_V1(ssl_issuer_field);
233 Datum
234 ssl_issuer_field(PG_FUNCTION_ARGS)
236 text *fieldname = PG_GETARG_TEXT_P(0);
237 Datum result;
239 if (!(MyProcPort->peer))
240 PG_RETURN_NULL();
242 result = X509_NAME_field_to_text(X509_get_issuer_name(MyProcPort->peer), fieldname);
244 if (!result)
245 PG_RETURN_NULL();
246 else
247 return result;
252 * Equivalent of X509_NAME_oneline that respects encoding
254 * This function converts X509_NAME structure to the text variable
255 * converting all textual data into current database encoding.
257 * Parameter: X509_NAME *name X509_NAME structure to be converted
259 * Returns: text datum which contains string representation of
260 * X509_NAME
262 Datum
263 X509_NAME_to_text(X509_NAME *name)
265 BIO *membuf = BIO_new(BIO_s_mem());
266 int i,
267 nid,
268 count = X509_NAME_entry_count(name);
269 X509_NAME_ENTRY *e;
270 ASN1_STRING *v;
271 const char *field_name;
272 size_t size;
273 char nullterm;
274 char *sp;
275 char *dp;
276 text *result;
278 (void) BIO_set_close(membuf, BIO_CLOSE);
279 for (i = 0; i < count; i++)
281 e = X509_NAME_get_entry(name, i);
282 nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
283 v = X509_NAME_ENTRY_get_data(e);
284 field_name = OBJ_nid2sn(nid);
285 if (!field_name)
286 field_name = OBJ_nid2ln(nid);
287 BIO_printf(membuf, "/%s=", field_name);
288 ASN1_STRING_print_ex(membuf, v,
289 ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
290 | ASN1_STRFLGS_UTF8_CONVERT));
293 /* ensure null termination of the BIO's content */
294 nullterm = '\0';
295 BIO_write(membuf, &nullterm, 1);
296 size = BIO_get_mem_data(membuf, &sp);
297 dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
298 size - 1,
299 PG_UTF8,
300 GetDatabaseEncoding());
301 result = cstring_to_text(dp);
302 if (dp != sp)
303 pfree(dp);
304 BIO_free(membuf);
306 PG_RETURN_TEXT_P(result);
311 * Returns current client certificate subject as one string
313 * This function returns distinguished name (subject) of the client
314 * certificate used in the current SSL connection, converting it into
315 * the current database encoding.
317 * Returns text datum.
319 PG_FUNCTION_INFO_V1(ssl_client_dn);
320 Datum
321 ssl_client_dn(PG_FUNCTION_ARGS)
323 if (!(MyProcPort->peer))
324 PG_RETURN_NULL();
325 return X509_NAME_to_text(X509_get_subject_name(MyProcPort->peer));
330 * Returns current client certificate issuer as one string
332 * This function returns issuer's distinguished name of the client
333 * certificate used in the current SSL connection, converting it into
334 * the current database encoding.
336 * Returns text datum.
338 PG_FUNCTION_INFO_V1(ssl_issuer_dn);
339 Datum
340 ssl_issuer_dn(PG_FUNCTION_ARGS)
342 if (!(MyProcPort->peer))
343 PG_RETURN_NULL();
344 return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));