/* * Copyright (C) 2013 Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ /* This file contains functions to handle X.509 certificate generation. */ #include "gnutls_int.h" #include #include #include "errors.h" #include #include #include #include typedef int (*set_dn_func) (void *, const char *oid, unsigned int raw_flag, const void *name, unsigned int name_size); static int dn_attr_crt_set(set_dn_func f, void *crt, const gnutls_datum_t * name, const gnutls_datum_t * val) { char _oid[MAX_OID_SIZE]; gnutls_datum_t tmp; const char *oid; int ret; unsigned i,j; if (name->size == 0 || val->size == 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); if (c_isdigit(name->data[0]) != 0) { if (name->size >= sizeof(_oid)) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); memcpy(_oid, name->data, name->size); _oid[name->size] = 0; oid = _oid; if (gnutls_x509_dn_oid_known(oid) == 0) { _gnutls_debug_log("Unknown OID: '%s'\n", oid); return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } } else { oid = _gnutls_ldap_string_to_oid((char *) name->data, name->size); } if (oid == NULL) { _gnutls_debug_log("Unknown DN attribute: '%.*s'\n", (int) name->size, name->data); return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); } if (val->data[0] == '#') return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); tmp.size = val->size; tmp.data = gnutls_malloc(tmp.size+1); if (tmp.data == NULL) { return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } for (j=i=0;isize && val->data[j] == '\\' && val->data[j+1] == ',') { tmp.data[i] = ','; j+=2; tmp.size--; } else { tmp.data[i] = val->data[j++]; } } tmp.data[tmp.size] = 0; ret = f(crt, oid, 0, tmp.data, tmp.size); gnutls_free(tmp.data); if (ret < 0) return gnutls_assert_val(ret); return 0; } static int read_attr_and_val(const char **ptr, gnutls_datum_t * name, gnutls_datum_t * val) { const unsigned char *p = (void *) *ptr; /* skip any space */ while (c_isspace(*p)) p++; /* Read the name */ name->data = (void *) p; while (*p != '=' && *p != 0 && !c_isspace(*p)) p++; name->size = p - name->data; /* skip any space */ while (c_isspace(*p)) p++; if (*p != '=') return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); p++; while (c_isspace(*p)) p++; /* Read value */ val->data = (void *) p; while (*p != 0 && (*p != ',' || (*p == ',' && *(p - 1) == '\\')) && *p != '\n') { p++; } val->size = p - (val->data); /* remove spaces from the end */ while(val->size > 0 && c_isspace(val->data[val->size-1])) { val->size--; } if (val->size == 0 || name->size == 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); *ptr = (void *) p; return 0; } static int crt_set_dn(set_dn_func f, void *crt, const char *dn, const char **err) { const char *p = dn; int ret; gnutls_datum_t name, val; if (crt == NULL || dn == NULL) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); /* For each element */ while (*p != 0 && *p != '\n') { if (err) *err = p; ret = read_attr_and_val(&p, &name, &val); if (ret < 0) return gnutls_assert_val(ret); /* skip spaces and look for comma */ while (c_isspace(*p)) p++; ret = dn_attr_crt_set(f, crt, &name, &val); if (ret < 0) return gnutls_assert_val(ret); if (err) *err = p; if (*p != ',' && *p != 0 && *p != '\n') return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); if (*p == ',') p++; } return 0; } /** * gnutls_x509_crt_set_dn: * @crt: a certificate of type #gnutls_x509_crt_t * @dn: a comma separated DN string (RFC4514) * @err: indicates the error position (if any) * * This function will set the DN on the provided certificate. * The input string should be plain ASCII or UTF-8 encoded. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crt_set_dn(gnutls_x509_crt_t crt, const char *dn, const char **err) { return crt_set_dn((set_dn_func) gnutls_x509_crt_set_dn_by_oid, crt, dn, err); } /** * gnutls_x509_crt_set_issuer_dn: * @crt: a certificate of type #gnutls_x509_crt_t * @dn: a comma separated DN string (RFC4514) * @err: indicates the error position (if any) * * This function will set the DN on the provided certificate. * The input string should be plain ASCII or UTF-8 encoded. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crt_set_issuer_dn(gnutls_x509_crt_t crt, const char *dn, const char **err) { return crt_set_dn((set_dn_func) gnutls_x509_crt_set_issuer_dn_by_oid, crt, dn, err); } /** * gnutls_x509_crq_set_dn: * @crq: a certificate of type #gnutls_x509_crq_t * @dn: a comma separated DN string (RFC4514) * @err: indicates the error position (if any) * * This function will set the DN on the provided certificate. * The input string should be plain ASCII or UTF-8 encoded. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crq_set_dn(gnutls_x509_crq_t crq, const char *dn, const char **err) { return crt_set_dn((set_dn_func) gnutls_x509_crq_set_dn_by_oid, crq, dn, err); }