diff --git a/src/format-dn.c b/src/format-dn.c index ea5a2c1..2df228b 100644 --- a/src/format-dn.c +++ b/src/format-dn.c @@ -1,399 +1,397 @@ /* format-dn.c - Functions to format an ASN.1 Distinuguished Name. * Copyright (C) 2001, 2004, 2007 Free Software Foundation, Inc. * Copyright (C) 2009 g10 Code GmbH. * * This file is part of GPA. * * GPA 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; either version 3 of the License, or * (at your option) any later version. * * GPA 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 . */ -/* +/* This code is based on code taken from GnuPG (sm/certdump.c). It has been converted to use only Glib stuff. */ #include #include #include #include "gpa.h" #include "format-dn.h" -struct dn_array_s +struct dn_array_s { char *key; char *value; int multivalued; int done; }; /* Remove trailing white spaces from STRING. */ static void trim_trailing_spaces (char *string) { char *p, *mark; - + for (mark=NULL, p=string; *p; p++) { if (g_ascii_isspace (*p)) { if (!mark) mark = p; } else mark = NULL; } if (mark) *mark = '\0' ; } /* Helper for the rfc2253 string parser. */ static const char * parse_dn_part (struct dn_array_s *array, const char *string) { static struct { const char *label; const char *oid; - } label_map[] = + } label_map[] = { /* Note: Take care we expect the LABEL not more than 9 bytes longer than the OID. */ {"EMail", "1.2.840.113549.1.9.1" }, {"T", "2.5.4.12" }, {"GN", "2.5.4.42" }, {"SN", "2.5.4.4" }, - {"NameDistinguisher", "0.2.262.1.10.7.20"}, + {"NameDistinguisher", "0.2.262.1.10.7.20"}, {"ADDR", "2.5.4.16" }, {"BC", "2.5.4.15" }, {"D", "2.5.4.13" }, {"PostalCode", "2.5.4.17" }, {"Pseudo", "2.5.4.65" }, {"SerialNumber", "2.5.4.5" }, + {"Callsign", "1.3.6.1.4.1.12348.1.1"}, {NULL, NULL} }; const char *s, *s1; size_t n; char *p; int i; /* Parse attributeType */ for (s = string+1; *s && *s != '='; s++) ; if (!*s) return NULL; /* error */ n = s - string; if (!n) return NULL; /* empty key */ /* We need to allocate a few bytes more due to the possible mapping from the shorter OID to the longer label. */ array->key = p = g_try_malloc (n+10); if (!array->key) return NULL; - memcpy (p, string, n); + memcpy (p, string, n); p[n] = 0; trim_trailing_spaces (p); if (g_ascii_isdigit (*p)) { for (i=0; label_map[i].label; i++ ) if ( !strcmp (p, label_map[i].oid) ) { strcpy (p, label_map[i].label); break; } } string = s + 1; if (*string == '#') - { + { /* Hexstring. */ string++; for (s=string; g_ascii_isxdigit (*s); s++) s++; n = s - string; if (!n || (n & 1)) return NULL; /* Empty or odd number of digits. */ n /= 2; array->value = p = g_try_malloc (n+1); if (!p) return NULL; for (s1=string; n; s1 += 2, n--, p++) { *(unsigned char *)p = xtoi_2 (s1); if (!*p) *p = 0x01; /* Better print a wrong value than truncating the string. */ } *p = 0; } else - { + { /* Regular v3 quoted string. */ for (n=0, s=string; *s; s++) { if (*s == '\\') - { + { /* Pair. */ s++; if (*s == ',' || *s == '=' || *s == '+' - || *s == '<' || *s == '>' || *s == '#' || *s == ';' + || *s == '<' || *s == '>' || *s == '#' || *s == ';' || *s == '\\' || *s == '\"' || *s == ' ') n++; else if (g_ascii_isxdigit (*s) && g_ascii_isxdigit(s[1])) { s++; n++; } else return NULL; /* Invalid escape sequence. */ } else if (*s == '\"') return NULL; /* Invalid encoding. */ else if (*s == ',' || *s == '=' || *s == '+' || *s == '<' || *s == '>' || *s == ';' ) - break; + break; else n++; } - + array->value = p = g_try_malloc (n+1); if (!p) return NULL; for (s=string; n; s++, n--) { if (*s == '\\') - { + { s++; if (g_ascii_isxdigit (*s)) { *(unsigned char *)p++ = xtoi_2 (s); s++; } else *p++ = *s; } else *p++ = *s; } *p = 0; } return s; } /* Parse a DN and return an array-ized one. This is not a validating parser and it does not support any old-stylish syntax; KSBA is expected to return only rfc2253 compatible strings. */ static struct dn_array_s * parse_dn (const char *string) { struct dn_array_s *array; size_t arrayidx, arraysize; int i; arraysize = 7; /* C,ST,L,O,OU,CN,email */ arrayidx = 0; array = g_try_malloc ((arraysize+1) * sizeof *array); if (!array) return NULL; while (*string) { while (*string == ' ') string++; if (!*string) break; /* Ready. */ if (arrayidx >= arraysize) - { + { struct dn_array_s *a2; arraysize += 5; a2 = g_try_realloc (array, (arraysize+1) * sizeof *array); if (!a2) goto failure; array = a2; } array[arrayidx].key = NULL; array[arrayidx].value = NULL; string = parse_dn_part (array+arrayidx, string); if (!string) goto failure; while (*string == ' ') string++; array[arrayidx].multivalued = (*string == '+'); array[arrayidx].done = 0; arrayidx++; if (*string && *string != ',' && *string != ';' && *string != '+') goto failure; /* Invalid delimiter. */ if (*string) string++; } array[arrayidx].key = NULL; array[arrayidx].value = NULL; return array; failure: for (i=0; i < arrayidx; i++) { g_free (array[i].key); g_free (array[i].value); } g_free (array); return NULL; } /* Append BUFFER to OUTOPUT while replacing all control characters and the characters in DELIMITERS by standard C escape sequences. */ -static void +static void append_sanitized (GString *output, const void *buffer, size_t length, const char *delimiters) { const unsigned char *p = buffer; size_t count = 0; - + for (; length; length--, p++, count++) { - if (*p < 0x20 + if (*p < 0x20 || *p == 0x7f - || (delimiters + || (delimiters && (strchr (delimiters, *p) || *p == '\\'))) { g_string_append_c (output, '\\'); if (*p == '\n') g_string_append_c (output, 'n'); else if (*p == '\r') g_string_append_c (output, 'r'); else if (*p == '\f') g_string_append_c (output, 'f'); else if (*p == '\v') g_string_append_c (output, 'v'); else if (*p == '\b') g_string_append_c (output, 'b'); else if (!*p) g_string_append_c (output, '0'); else g_string_append_printf (output, "x%02x", *p); } else g_string_append_c (output, *p); } } /* Print a DN part to STREAM or if STREAM is NULL to FP. */ static void print_dn_part (GString *output, struct dn_array_s *dn, const char *key) { struct dn_array_s *first_dn = dn; for (; dn->key; dn++) { if (!dn->done && !strcmp (dn->key, key)) { /* Forward to the last multi-valued RDN, so that we can print them all in reverse in the correct order. Note that this overrides the the standard sequence but that seems to a reasonable thing to do with multi-valued RDNs. */ while (dn->multivalued && dn[1].key) dn++; next: if (!dn->done && dn->value && *dn->value) { g_string_append_printf (output, "/%s=", dn->key); append_sanitized (output, dn->value, strlen (dn->value), "/"); } dn->done = 1; if (dn > first_dn && dn[-1].multivalued) { dn--; goto next; } } } } /* Print all parts of a DN in a "standard" sequence. We first print all the known parts, followed by the uncommon ones. */ static void print_dn_parts (GString *output, struct dn_array_s *dn) { const char *stdpart[] = { - "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL + "CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL }; int i; - + for (i=0; stdpart[i]; i++) print_dn_part (output, dn, stdpart[i]); /* Now print the rest without any specific ordering */ for (; dn->key; dn++) print_dn_part (output, dn, dn->key); } /* Format an RFC2253 encoded DN or GeneralName. Caller needs to release the return ed string. This function will never return NULL. */ char * -gpa_format_dn (const char *name) +gpa_format_dn (const char *name) { char *retval = NULL; - + if (!name) retval = g_strdup (_("[Error - No name]")); else if (*name == '<') { const char *s = strchr (name+1, '>'); if (s) retval = g_strndup (name+1, s - (name+1)); } else if (*name == '(') retval = g_strdup (_("[Error - Encoding not supported]")); else if (g_ascii_isalnum (*name)) { struct dn_array_s *dn; int i; dn = parse_dn (name); if (dn) { GString *output = g_string_sized_new (strlen (name)); - print_dn_parts (output, dn); + print_dn_parts (output, dn); retval = g_string_free (output, FALSE); for (i=0; dn[i].key; i++) { g_free (dn[i].key); g_free (dn[i].value); } g_free (dn); } } - + if (!retval) retval = g_strdup (_("[Error - Invalid encoding]")); return retval; } - - -