static HRESULT parse_pubkey(IAssemblyNameImpl *name, LPCWSTR pubkey) { int i; BYTE val; static const WCHAR nullstr[] = {'n','u','l','l',0}; if(lstrcmpiW(pubkey, nullstr) == 0) return FUSION_E_PRIVATE_ASM_DISALLOWED; if (lstrlenW(pubkey) < CHARS_PER_PUBKEY) return FUSION_E_INVALID_NAME; for (i = 0; i < CHARS_PER_PUBKEY; i++) if (!is_hex(pubkey[i])) return FUSION_E_INVALID_NAME; name->haspubkey = TRUE; for (i = 0; i < CHARS_PER_PUBKEY; i += 2) { val = (hextobyte(pubkey[i]) << 4) + hextobyte(pubkey[i + 1]); name->pubkey[i / 2] = val; } return S_OK; }
/**************** * Get the session key from the given string. * String is supposed to be formatted as this: * <algo-id>:<even-number-of-hex-digits> */ int get_override_session_key( DEK *dek, const char *string ) { const char *s; int i; if ( !string ) return G10ERR_BAD_KEY; dek->algo = atoi(string); if ( dek->algo < 1 ) return G10ERR_BAD_KEY; if ( !(s = strchr ( string, ':' )) ) return G10ERR_BAD_KEY; s++; for(i=0; i < DIM(dek->key) && *s; i++, s +=2 ) { int c = hextobyte ( s ); if (c == -1) return G10ERR_BAD_KEY; dek->key[i] = c; } if ( *s ) return G10ERR_BAD_KEY; dek->keylen = i; return 0; }
BOOL hitag2_config_block_show(BYTE *config, BYTE *password, BYTE *key) { BYTE value= hextobyte(config); // first byte only used as config UserMessage(" PWD Block (1): %.8s ", password); printhexreadable(password, 4); UserMessage("\r\n\r\n Key Block (2): %.8s ", key); printhexreadable(key, 4); UserMessage("\r\n\r\n Config Block (3): %.8s\r\n\r\n", config); UserMessageNum(" Page 1 & 2: %d = ", GET_CONFIG(value, HITAG2_MASK_PAGE_1_2_OTP_PROTECT, HITAG2_SHIFT_PAGE_1_2_OTP_PROTECT)); if(GET_CONFIG(value, HITAG2_MASK_SECURITY, HITAG2_SHIFT_SECURITY)) UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_PAGE_1_2_OTP_PROTECT, HITAG2_SHIFT_PAGE_1_2_OTP_PROTECT) ? "No Read / No Write" : "Read / Write"); else UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_PAGE_1_2_OTP_PROTECT, HITAG2_SHIFT_PAGE_1_2_OTP_PROTECT) ? "Page 1: No Read / No Write, Page 2: Read Only" : "Read / Write"); UserMessageNum(" Page 3: %d = ", GET_CONFIG(value, HITAG2_MASK_PAGE_3_OTP_PROTECT, HITAG2_SHIFT_PAGE_3_OTP_PROTECT)); UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_PAGE_3_OTP_PROTECT, HITAG2_SHIFT_PAGE_3_OTP_PROTECT) ? "Read Only" : "Read / Write"); UserMessageNum(" Page 4 & 5: %d = ", GET_CONFIG(value, HITAG2_MASK_PAGE_4_5_PROTECT, HITAG2_SHIFT_PAGE_4_5_PROTECT)); UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_PAGE_4_5_PROTECT, HITAG2_SHIFT_PAGE_4_5_PROTECT) ? "Read Only" : "Read / Write"); UserMessageNum(" Page 6 & 7: %d = ", GET_CONFIG(value, HITAG2_MASK_PAGE_6_7_PROTECT, HITAG2_SHIFT_PAGE_6_7_PROTECT)); UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_PAGE_6_7_PROTECT, HITAG2_SHIFT_PAGE_6_7_PROTECT) ? "Read Only" : "Read / Write"); UserMessageNum(" Security: %d = ", GET_CONFIG(value, HITAG2_MASK_SECURITY, HITAG2_SHIFT_SECURITY)); UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_SECURITY, HITAG2_SHIFT_SECURITY) ? "Crypto" : "Password"); UserMessageNum(" Mode: %d = ", GET_CONFIG(value, HITAG2_MASK_MODE, HITAG2_SHIFT_MODE)); UserMessage("%s\r\n", (BYTE *) Hitag2_Modes[GET_CONFIG(value, HITAG2_MASK_MODE, HITAG2_SHIFT_MODE)]); UserMessageNum(" Modulation: %d = ", GET_CONFIG(value, HITAG2_MASK_MODULATION, HITAG2_SHIFT_MODULATION)); UserMessage("%s\r\n", GET_CONFIG(value, HITAG2_MASK_MODULATION, HITAG2_SHIFT_MODULATION) ? "BiPhase" : "Manchester"); UserMessage("\r\n PWD Block (3): %.6s ", config + 2); printhexreadable(config + 2, 3); UserMessage("%s", "\r\n"); return TRUE; }
float hextofloat(std::string data) { if (data.find(',') < 8 || data.length() != 8) { return NAN; } unsigned char chdata[4]; for (int i=0; i<4; i++) { std::string substr = data.substr(i*2, (i*2)+2); chdata[i] = hextobyte(substr); } float output = *(float *)((void *)chdata); //floating point bit level hack return output; }
static char * format_fingerprint ( const char *s ) { int i, c; byte fpr[20]; for (i=0; i < 20 && *s; ) { if ( *s == ' ' || *s == '\t' ) { s++; continue; } c = hextobyte(s); if (c == -1) { return NULL; } fpr[i++] = c; s += 2; } return gcry_xstrdup ( fpr ); }
/* Return a value describing the the class of PATTERN. The offset of the actual string to be used for the comparison is stored at R_OFFSET. The offset of the serialnumer is stored at R_SN_OFFSET. */ static enum pattern_class classify_pattern (const char *pattern, size_t *r_offset, size_t *r_sn_offset) { enum pattern_class result; const char *s; int hexprefix = 0; int hexlength; *r_offset = *r_sn_offset = 0; /* Skip leading spaces. */ for(s = pattern; *s && spacep (s); s++ ) ; switch (*s) { case 0: /* Empty string is an error. */ result = PATTERN_UNKNOWN; break; case '.': /* An email address, compare from end. */ result = PATTERN_UNKNOWN; /* Not implemented. */ break; case '<': /* An email address. */ result = PATTERN_EMAIL; s++; break; case '@': /* Part of an email address. */ result = PATTERN_EMAIL_SUBSTR; s++; break; case '=': /* Exact compare. */ result = PATTERN_UNKNOWN; /* Does not make sense for X.509. */ break; case '*': /* Case insensitive substring search. */ result = PATTERN_SUBSTR; s++; break; case '+': /* Compare individual words. */ result = PATTERN_UNKNOWN; /* Not implemented. */ break; case '/': /* Subject's DN. */ s++; if (!*s || spacep (s)) result = PATTERN_UNKNOWN; /* No DN or prefixed with a space. */ else result = PATTERN_SUBJECT; break; case '#': /* Serial number or issuer DN. */ { const char *si; s++; if ( *s == '/') { /* An issuer's DN is indicated by "#/" */ s++; if (!*s || spacep (s)) result = PATTERN_UNKNOWN; /* No DN or prefixed with a space. */ else result = PATTERN_ISSUER; } else { /* Serialnumber + optional issuer ID. */ for (si=s; *si && *si != '/'; si++) if (!strchr("01234567890abcdefABCDEF", *si)) break; if (*si && *si != '/') result = PATTERN_UNKNOWN; /* Invalid digit in serial number. */ else { *r_sn_offset = s - pattern; if (!*si) result = PATTERN_SERIALNO; else { s = si+1; if (!*s || spacep (s)) result = PATTERN_UNKNOWN; /* No DN or prefixed with a space. */ else result = PATTERN_SERIALNO_ISSUER; } } } } break; case ':': /* Unified fingerprint. */ { const char *se, *si; int i; se = strchr (++s, ':'); if (!se) result = PATTERN_UNKNOWN; else { for (i=0, si=s; si < se; si++, i++ ) if (!strchr("01234567890abcdefABCDEF", *si)) break; if ( si < se ) result = PATTERN_UNKNOWN; /* Invalid digit. */ else if (i == 32) result = PATTERN_FINGERPRINT16; else if (i == 40) result = PATTERN_FINGERPRINT20; else result = PATTERN_UNKNOWN; /* Invalid length for a fingerprint. */ } } break; case '&': /* Keygrip. */ result = PATTERN_UNKNOWN; /* Not implemented. */ break; default: if (s[0] == '0' && s[1] == 'x') { hexprefix = 1; s += 2; } hexlength = strspn(s, "0123456789abcdefABCDEF"); /* Check if a hexadecimal number is terminated by EOS or blank. */ if (hexlength && s[hexlength] && !spacep (s+hexlength)) { /* If the "0x" prefix is used a correct termination is required. */ if (hexprefix) { result = PATTERN_UNKNOWN; break; /* switch */ } hexlength = 0; /* Not a hex number. */ } if (hexlength == 8 || (!hexprefix && hexlength == 9 && *s == '0')) { if (hexlength == 9) s++; result = PATTERN_SHORT_KEYID; } else if (hexlength == 16 || (!hexprefix && hexlength == 17 && *s == '0')) { if (hexlength == 17) s++; result = PATTERN_LONG_KEYID; } else if (hexlength == 32 || (!hexprefix && hexlength == 33 && *s == '0')) { if (hexlength == 33) s++; result = PATTERN_FINGERPRINT16; } else if (hexlength == 40 || (!hexprefix && hexlength == 41 && *s == '0')) { if (hexlength == 41) s++; result = PATTERN_FINGERPRINT20; } else if (!hexprefix) { /* The fingerprints used with X.509 are often delimited by colons, so we try to single this case out. */ result = PATTERN_UNKNOWN; hexlength = strspn (s, ":0123456789abcdefABCDEF"); if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength))) { int i, c; for (i=0; i < 20; i++, s += 3) { c = hextobyte(s); if (c == -1 || (i < 19 && s[2] != ':')) break; } if (i == 20) result = PATTERN_FINGERPRINT20; } if (result == PATTERN_UNKNOWN) /* Default to substring match. */ { result = PATTERN_SUBSTR; } } else /* A hex number with a prefix but with a wrong length. */ result = PATTERN_UNKNOWN; } if (result != PATTERN_UNKNOWN) *r_offset = s - pattern; return result; }
static int classify_user_id (const char *name, KEYDB_SEARCH_DESC *desc, int *force_exact ) { const char *s; int hexprefix = 0; int hexlength; int mode = 0; /* clear the structure so that the mode field is set to zero unless * we set it to the correct value right at the end of this function */ memset (desc, 0, sizeof *desc); *force_exact = 0; /* Skip leading spaces. Fixme: what about trailing white space? */ for(s = name; *s && spacep (s); s++ ) ; switch (*s) { case 0: /* empty string is an error */ return 0; case '.': /* an email address, compare from end */ mode = KEYDB_SEARCH_MODE_MAILEND; s++; desc->u.name = s; break; case '<': /* an email address */ mode = KEYDB_SEARCH_MODE_MAIL; s++; desc->u.name = s; break; case '@': /* part of an email address */ mode = KEYDB_SEARCH_MODE_MAILSUB; s++; desc->u.name = s; break; case '=': /* exact compare */ mode = KEYDB_SEARCH_MODE_EXACT; s++; desc->u.name = s; break; case '*': /* case insensitive substring search */ mode = KEYDB_SEARCH_MODE_SUBSTR; s++; desc->u.name = s; break; case '+': /* compare individual words */ mode = KEYDB_SEARCH_MODE_WORDS; s++; desc->u.name = s; break; case '/': /* subject's DN */ s++; if (!*s || spacep (s)) return 0; /* no DN or prefixed with a space */ desc->u.name = s; mode = KEYDB_SEARCH_MODE_SUBJECT; break; case '#': { const char *si; s++; if ( *s == '/') { /* "#/" indicates an issuer's DN */ s++; if (!*s || spacep (s)) return 0; /* no DN or prefixed with a space */ desc->u.name = s; mode = KEYDB_SEARCH_MODE_ISSUER; } else { /* serialnumber + optional issuer ID */ for (si=s; *si && *si != '/'; si++) { if (!strchr("01234567890abcdefABCDEF", *si)) return 0; /* invalid digit in serial number*/ } desc->sn = (const unsigned char*)s; desc->snlen = -1; if (!*si) mode = KEYDB_SEARCH_MODE_SN; else { s = si+1; if (!*s || spacep (s)) return 0; /* no DN or prefixed with a space */ desc->u.name = s; mode = KEYDB_SEARCH_MODE_ISSUER_SN; } } } break; case ':': /*Unified fingerprint */ { const char *se, *si; int i; se = strchr (++s,':'); if (!se) return 0; for (i=0,si=s; si < se; si++, i++ ) { if (!strchr("01234567890abcdefABCDEF", *si)) return 0; /* invalid digit */ } if (i != 32 && i != 40) return 0; /* invalid length of fpr*/ for (i=0,si=s; si < se; i++, si +=2) desc->u.fpr[i] = hextobyte(si); for (; i < 20; i++) desc->u.fpr[i]= 0; s = se + 1; mode = KEYDB_SEARCH_MODE_FPR; } break; case '&': /* Keygrip*/ { if (hex2bin (s+1, desc->u.grip, 20) < 0) return 0; /* Invalid. */ mode = KEYDB_SEARCH_MODE_KEYGRIP; } break; default: if (s[0] == '0' && s[1] == 'x') { hexprefix = 1; s += 2; } hexlength = strspn(s, "0123456789abcdefABCDEF"); if (hexlength >= 8 && s[hexlength] =='!') { *force_exact = 1; hexlength++; /* just for the following check */ } /* check if a hexadecimal number is terminated by EOS or blank */ if (hexlength && s[hexlength] && !spacep (s+hexlength)) { if (hexprefix) /* a "0x" prefix without correct */ return 0; /* termination is an error */ /* The first chars looked like a hex number, but really is not */ hexlength = 0; } if (*force_exact) hexlength--; /* remove the bang */ if (hexlength == 8 || (!hexprefix && hexlength == 9 && *s == '0')) { /* short keyid */ unsigned long kid; if (hexlength == 9) s++; kid = strtoul( s, NULL, 16 ); desc->u.kid[4] = kid >> 24; desc->u.kid[5] = kid >> 16; desc->u.kid[6] = kid >> 8; desc->u.kid[7] = kid; mode = KEYDB_SEARCH_MODE_SHORT_KID; } else if (hexlength == 16
unsigned char fromhex(const std::string& x, size_t idx) { return (hextobyte(x[idx * 2]) << 4) | (hextobyte(x[idx * 2 + 1])); }
/**************** * Scan the provided buffer and return the S expression in our internal * format. Returns a newly allocated expression. If erroff is not NULL and * a parsing error has occured, the offset into buffer will be returned. * If ARGFLAG is true, the function supports some printf like * expressions. * These are: * %m - MPI * %s - string (no autoswitch to secure allocation) * %d - integer stored as string (no autoswitch to secure allocation) * %b - memory buffer; this takes _two_ arguments: an integer with the * length of the buffer and a pointer to the buffer. * all other format elements are currently not defined and return an error. * this includes the "%%" sequence becauce the percent sign is not an * allowed character. * FIXME: We should find a way to store the secure-MPIs not in the string * but as reference to somewhere - this can help us to save huge amounts * of secure memory. The problem is, that if only one element is secure, all * other elements are automagicaly copied to secure memory too, so the most * common operation gcry_sexp_cdr_mpi() will always return a secure MPI * regardless whether it is needed or not. */ static gcry_error_t sexp_sscan (gcry_sexp_t *retsexp, size_t *erroff, const char *buffer, size_t length, int argflag, va_list arg_ptr, void **arg_list) { gcry_err_code_t err = GPG_ERR_NO_ERROR; static const char tokenchars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789-./_:*+="; const char *p; size_t n; const char *digptr = NULL; const char *quoted = NULL; const char *tokenp = NULL; const char *hexfmt = NULL; const char *base64 = NULL; const char *disphint = NULL; const char *percent = NULL; int hexcount = 0; int quoted_esc = 0; int datalen = 0; size_t dummy_erroff; struct make_space_ctx c; int arg_counter = 0; int level = 0; /* FIXME: invent better error codes (?). */ if (! erroff) erroff = &dummy_erroff; /* Depending on wether ARG_LIST is non-zero or not, this macro gives us the next argument, either from the variable argument list as specified by ARG_PTR or from the argument array ARG_LIST. */ #define ARG_NEXT(storage, type) \ do \ { \ if (! arg_list) \ storage = va_arg (arg_ptr, type); \ else \ storage = *((type *) (arg_list[arg_counter++])); \ } \ while (0) #define MAKE_SPACE(n) do { make_space ( &c, (n) ); } while (0) #define STORE_LEN(p,n) do { \ DATALEN ashort = (n); \ memcpy ( (p), &ashort, sizeof(ashort) ); \ (p) += sizeof (ashort); \ } while (0) /* We assume that the internal representation takes less memory * than the provided one. However, we add space for one extra datalen * so that the code which does the ST_CLOSE can use MAKE_SPACE */ c.allocated = length + sizeof(DATALEN); if (buffer && length && gcry_is_secure (buffer)) c.sexp = gcry_xmalloc_secure (sizeof *c.sexp + c.allocated - 1); else c.sexp = gcry_xmalloc (sizeof *c.sexp + c.allocated - 1); c.pos = c.sexp->d; for (p = buffer, n = length; n; p++, n--) { if (tokenp && (! hexfmt)) { if (strchr (tokenchars, *p)) continue; else { datalen = p - tokenp; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, tokenp, datalen); c.pos += datalen; tokenp = NULL; } } if (quoted) { if (quoted_esc) { switch (*p) { case 'b': case 't': case 'v': case 'n': case 'f': case 'r': case '"': case '\'': case '\\': quoted_esc = 0; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': if (! ((n > 2) && (p[1] >= '0') && (p[1] <= '7') && (p[2] >= '0') && (p[2] <= '7'))) { *erroff = p - buffer; /* Invalid octal value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION); } p += 2; n -= 2; quoted_esc = 0; break; case 'x': if (! ((n > 2) && isxdigit(p[1]) && isxdigit(p[2]))) { *erroff = p - buffer; /* Invalid hex value. */ err = GPG_ERR_SEXP_BAD_QUOTATION; //return gcry_error (GPG_ERR_SEXP_BAD_QUOTATION); } p += 2; n -= 2; quoted_esc = 0; break; case '\r': /* ignore CR[,LF] */ if (n && (p[1] == '\n')) { p++; n--; } quoted_esc = 0; break; case '\n': /* ignore LF[,CR] */ if (n && (p[1] == '\r')) { p++; n--; } quoted_esc = 0; break; default: *erroff = p - buffer; /* Invalid quoted string escape. */ err = GPG_ERR_SEXP_BAD_QUOTATION; } } else if (*p == '\\') quoted_esc = 1; else if (*p == '\"') { /* Keep it easy - we know that the unquoted string will never be larger. */ char *save; size_t len; quoted++; /* Skip leading quote. */ MAKE_SPACE (p - quoted); *c.pos++ = ST_DATA; save = c.pos; STORE_LEN (c.pos, 0); /* Will be fixed up later. */ len = unquote_string (quoted, p - quoted, c.pos); c.pos += len; STORE_LEN (save, len); quoted = NULL; } } else if (hexfmt) { if (isxdigit (*p)) hexcount++; else if (*p == '#') { if ((hexcount & 1)) { *erroff = p - buffer; err = GPG_ERR_SEXP_ODD_HEX_NUMBERS; } datalen = hexcount / 2; MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); for (hexfmt++; hexfmt < p; hexfmt++) { if (isspace (*hexfmt)) continue; *c.pos++ = hextobyte (hexfmt); hexfmt++; } hexfmt = NULL; } else if (! isspace (*p)) { *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_HEX_CHAR; } } else if (base64) { if (*p == '|') base64 = NULL; } else if (digptr) { if (isdigit (*p)) ; else if (*p == ':') { datalen = atoi (digptr); /* FIXME: check for overflow. */ digptr = NULL; if (datalen > n - 1) { *erroff = p - buffer; /* Buffer too short. */ err = GPG_ERR_SEXP_STRING_TOO_LONG; } /* Make a new list entry. */ MAKE_SPACE (datalen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, datalen); memcpy (c.pos, p + 1, datalen); c.pos += datalen; n -= datalen; p += datalen; } else if (*p == '\"') { digptr = NULL; /* We ignore the optional length. */ quoted = p; quoted_esc = 0; } else if (*p == '#') { digptr = NULL; /* We ignore the optional length. */ hexfmt = p; hexcount = 0; } else if (*p == '|') { digptr = NULL; /* We ignore the optional length. */ base64 = p; } else { *erroff = p - buffer; err = GPG_ERR_SEXP_INV_LEN_SPEC; } } else if (percent) { if (*p == 'm') { /* Insert an MPI. */ gcry_mpi_t m; size_t nm = 0; ARG_NEXT (m, gcry_mpi_t); if (gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &nm, m)) BUG (); MAKE_SPACE (nm); if ((! gcry_is_secure (c.sexp->d)) && gcry_mpi_get_flag ( m, GCRYMPI_FLAG_SECURE)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_xmalloc_secure (sizeof *newsexp + c.allocated - 1); newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, nm); if (gcry_mpi_print (GCRYMPI_FMT_STD, c.pos, nm, &nm, m)) BUG (); c.pos += nm; } else if (*p == 's') { /* Insert an string. */ const char *astr; size_t alen; ARG_NEXT (astr, const char *); alen = strlen (astr); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'b') { /* Insert a memory buffer. */ const char *astr; int alen; ARG_NEXT (alen, int); ARG_NEXT (astr, const char *); MAKE_SPACE (alen); if (alen && !gcry_is_secure (c.sexp->d) && gcry_is_secure (astr)) { /* We have to switch to secure allocation. */ gcry_sexp_t newsexp; byte *newhead; newsexp = gcry_xmalloc_secure (sizeof *newsexp + c.allocated - 1); newhead = newsexp->d; memcpy (newhead, c.sexp->d, (c.pos - c.sexp->d)); c.pos = newhead + (c.pos - c.sexp->d); gcry_free (c.sexp); c.sexp = newsexp; } *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, astr, alen); c.pos += alen; } else if (*p == 'd') { /* Insert an integer as string. */ int aint; size_t alen; char buf[20]; ARG_NEXT (aint, int); sprintf (buf, "%d", aint); alen = strlen (buf); MAKE_SPACE (alen); *c.pos++ = ST_DATA; STORE_LEN (c.pos, alen); memcpy (c.pos, buf, alen); c.pos += alen; } else { *erroff = p - buffer; /* Invalid format specifier. */ err = GPG_ERR_SEXP_INV_LEN_SPEC; } percent = NULL; } else if (*p == '(') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; } MAKE_SPACE (0); *c.pos++ = ST_OPEN; level++; } else if (*p == ')') { /* Walk up. */ if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; } MAKE_SPACE (0); *c.pos++ = ST_CLOSE; level--; } else if (*p == '\"') { quoted = p; quoted_esc = 0; } else if (*p == '#') { hexfmt = p; hexcount = 0; } else if (*p == '|') base64 = p; else if (*p == '[') { if (disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_NESTED_DH; } disphint = p; } else if (*p == ']') { if (! disphint) { *erroff = p - buffer; /* Open display hint. */ err = GPG_ERR_SEXP_UNMATCHED_DH; } disphint = NULL; } else if (isdigit (*p)) { if (*p == '0') { /* A length may not begin with zero. */ *erroff = p - buffer; err = GPG_ERR_SEXP_ZERO_PREFIX; } digptr = p; } else if (strchr (tokenchars, *p)) tokenp = p; else if (isspace (*p)) ; else if (*p == '{') { /* fixme: handle rescanning: we can do this by saving our current state and start over at p+1 -- Hmmm. At this point here we are in a well defined state, so we don't need to save it. Great. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; } else if (strchr ("&\\", *p)) { /* Reserved punctuation. */ *erroff = p - buffer; err = GPG_ERR_SEXP_UNEXPECTED_PUNC; } else if (argflag && (*p == '%')) percent = p; else { /* Bad or unavailable. */ *erroff = p - buffer; err = GPG_ERR_SEXP_BAD_CHARACTER; } } MAKE_SPACE (0); *c.pos++ = ST_STOP; if (level) err = GPG_ERR_SEXP_UNMATCHED_PAREN; if (err) { /* Error -> deallocate. */ if (c.sexp) { /* Extra paranoid wipe on error. */ if (gcry_is_secure (c.sexp)) wipememory (c.sexp, sizeof (struct gcry_sexp) + c.allocated - 1); gcry_free (c.sexp); } /* This might be expected by existing code... */ *retsexp = NULL; } else *retsexp = normalize (c.sexp); return gcry_error (err); #undef MAKE_SPACE #undef STORE_LEN }
/* Returns a keyrec (which must be freed) once a key is complete, and NULL otherwise. Call with a NULL keystring once key parsing is complete to return any unfinished keys. */ static struct keyrec * parse_keyrec(char *keystring) { /* FIXME: Remove the static and put the data into the parms we use for the caller anyway. */ static struct keyrec *work=NULL; struct keyrec *ret=NULL; char *record; int i; if(keystring==NULL) { if(work==NULL) return NULL; else if(work->desc.mode==KEYDB_SEARCH_MODE_NONE) { xfree(work); return NULL; } else { ret=work; work=NULL; return ret; } } if(work==NULL) { work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } trim_trailing_ws (keystring, strlen (keystring)); if((record=strsep(&keystring,":"))==NULL) return ret; if(ascii_strcasecmp("pub",record)==0) { char *tok; gpg_error_t err; if(work->desc.mode) { ret=work; work=xmalloc_clear(sizeof(struct keyrec)); work->uidbuf=iobuf_temp(); } if((tok=strsep(&keystring,":"))==NULL) return ret; err = classify_user_id (tok, &work->desc, 1); if (err || (work->desc.mode != KEYDB_SEARCH_MODE_SHORT_KID && work->desc.mode != KEYDB_SEARCH_MODE_LONG_KID && work->desc.mode != KEYDB_SEARCH_MODE_FPR16 && work->desc.mode != KEYDB_SEARCH_MODE_FPR20)) { work->desc.mode=KEYDB_SEARCH_MODE_NONE; return ret; } /* Note all items after this are optional. This allows us to have a pub line as simple as pub:keyid and nothing else. */ work->lines++; if((tok=strsep(&keystring,":"))==NULL) return ret; work->type=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; work->size=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->createtime=0; else work->createtime=atoi(tok); if((tok=strsep(&keystring,":"))==NULL) return ret; if(atoi(tok)<=0) work->expiretime=0; else { work->expiretime=atoi(tok); /* Force the 'e' flag on if this key is expired. */ if(work->expiretime<=make_timestamp()) work->flags|=4; } if((tok=strsep(&keystring,":"))==NULL) return ret; while(*tok) switch(*tok++) { case 'r': case 'R': work->flags|=1; break; case 'd': case 'D': work->flags|=2; break; case 'e': case 'E': work->flags|=4; break; } } else if(ascii_strcasecmp("uid",record)==0 && work->desc.mode) { char *userid,*tok,*decoded; if((tok=strsep(&keystring,":"))==NULL) return ret; if(strlen(tok)==0) return ret; userid=tok; /* By definition, de-%-encoding is always smaller than the original string so we can decode in place. */ i=0; while(*tok) if(tok[0]=='%' && tok[1] && tok[2]) { int c; userid[i] = (c=hextobyte(&tok[1])) == -1 ? '?' : c; i++; tok+=3; } else userid[i++]=*tok++; /* We don't care about the other info provided in the uid: line since no keyserver supports marking userids with timestamps or revoked/expired/disabled yet. */ /* No need to check for control characters, as utf8_to_native does this for us. */ decoded=utf8_to_native(userid,i,0); if(strlen(decoded)>opt.screen_columns-10) decoded[opt.screen_columns-10]='\0'; iobuf_writestr(work->uidbuf,decoded); xfree(decoded); iobuf_writestr(work->uidbuf,"\n\t"); work->lines++; } /* Ignore any records other than "pri" and "uid" for easy future growth. */ return ret; }