/* Parse a TOFU_STATS_LONG line and store it in the last tofu info of SIG. */ static gpgme_error_t parse_tofu_stats_long (gpgme_signature_t sig, char *args, int raw) { gpgme_error_t err; gpgme_tofu_info_t ti; char *p; if (!sig->tofu) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */ for (ti = sig->tofu; ti->next; ti = ti->next) ; if (ti->description) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen. */ err = _gpgme_decode_percent_string (args, &ti->description, 0, 0); if (err) return err; /* Remove the non-breaking spaces. */ if (!raw) { for (p = ti->description; *p; p++) if (*p == '~') *p = ' '; } return 0; }
static gpgme_error_t parse_enc_to (char *args, gpgme_recipient_t *recp, gpgme_protocol_t protocol) { gpgme_recipient_t rec; char *tail; int i; rec = malloc (sizeof (*rec)); if (!rec) return gpg_error_from_syserror (); rec->next = NULL; rec->keyid = rec->_keyid; rec->status = 0; for (i = 0; i < sizeof (rec->_keyid) - 1; i++) { if (args[i] == '\0' || args[i] == ' ') break; rec->_keyid[i] = args[i]; } rec->_keyid[i] = '\0'; args = &args[i]; if (*args != '\0' && *args != ' ') { free (rec); return trace_gpg_error (GPG_ERR_INV_ENGINE); } while (*args == ' ') args++; if (*args) { gpg_err_set_errno (0); rec->pubkey_algo = _gpgme_map_pk_algo (strtol (args, &tail, 0), protocol); if (errno || args == tail || *tail != ' ') { /* The crypto backend does not behave. */ free (rec); return trace_gpg_error (GPG_ERR_INV_ENGINE); } } /* FIXME: The key length is always 0 right now, so no need to parse it. */ *recp = rec; return 0; }
/* Parse a TOFU_USER line and put the info into SIG. */ static gpgme_error_t parse_tofu_user (gpgme_signature_t sig, char *args) { gpg_error_t err; char *tail; gpgme_tofu_info_t ti, ti2; tail = strchr (args, ' '); if (!tail || tail == args) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No fingerprint. */ *tail++ = 0; ti = calloc (1, sizeof *ti); if (!ti) return gpg_error_from_syserror (); ti->fpr = strdup (args); if (!ti->fpr) { free (ti); return gpg_error_from_syserror (); } args = tail; tail = strchr (args, ' '); if (tail == args) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No addr-spec. */ if (tail) *tail = 0; err = _gpgme_decode_percent_string (args, &ti->address, 0, 0); if (err) { free (ti); return err; } /* Append to the tofu info list. */ if (!sig->tofu) sig->tofu = ti; else { for (ti2 = sig->tofu; ti2->next; ti2 = ti2->next) ; ti2->next = ti; } return 0; }
static gpgme_error_t gpgconf_config_load_cb (void *hook, char *line) { gpgme_conf_comp_t *comp_p = hook; gpgme_conf_comp_t comp = *comp_p; #define NR_FIELDS 16 char *field[NR_FIELDS]; int fields = 0; while (line && fields < NR_FIELDS) { field[fields++] = line; line = strchr (line, ':'); if (line) *(line++) = '\0'; } /* We require at least the first 3 fields. */ if (fields < 2) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Find the pointer to the new component in the list. */ while (comp && comp->next) comp = comp->next; if (comp) comp_p = &comp->next; comp = calloc (1, sizeof (*comp)); if (!comp) return gpg_error_from_syserror (); /* Prepare return value. */ comp->_last_opt_p = &comp->options; *comp_p = comp; comp->name = strdup (field[0]); if (!comp->name) return gpg_error_from_syserror (); comp->description = strdup (field[1]); if (!comp->description) return gpg_error_from_syserror (); if (fields >= 3) { comp->program_name = strdup (field[2]); if (!comp->program_name) return gpg_error_from_syserror (); } return 0; }
/* Parse a FAILURE status line and return the error code. ARGS is modified to contain the location part. */ gpgme_error_t _gpgme_parse_failure (char *args) { char *where, *which; where = strchr (args, ' '); if (!where) return trace_gpg_error (GPG_ERR_INV_ENGINE); *where = '\0'; which = where + 1; where = strchr (which, ' '); if (where) *where = '\0'; where = args; return atoi (which); }
/* Parse an error status line and if SET_STATUS is true update the result status as appropriate. With SET_STATUS being false, only check for an error. */ static gpgme_error_t parse_error (gpgme_signature_t sig, char *args, int set_status) { gpgme_error_t err; char *where = strchr (args, ' '); char *which; if (where) { *where = '\0'; which = where + 1; where = strchr (which, ' '); if (where) *where = '\0'; where = args; } else return trace_gpg_error (GPG_ERR_INV_ENGINE); err = atoi (which); if (!strcmp (where, "proc_pkt.plaintext") && gpg_err_code (err) == GPG_ERR_BAD_DATA) { /* This indicates a double plaintext. The only solid way to handle this is by failing the oepration. */ return gpg_error (GPG_ERR_BAD_DATA); } else if (!set_status) ; else if (!strcmp (where, "verify.findkey")) sig->status = err; else if (!strcmp (where, "verify.keyusage") && gpg_err_code (err) == GPG_ERR_WRONG_KEY_USAGE) sig->wrong_key_usage = 1; return 0; }
gpgme_error_t _gpgme_verify_status_handler (void *priv, gpgme_status_code_t code, char *args) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; void *hook; op_data_t opd; gpgme_signature_t sig; char *end; err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, &hook, -1, NULL); opd = hook; if (err) return err; sig = opd->current_sig; switch (code) { case GPGME_STATUS_NEWSIG: if (sig) calc_sig_summary (sig); err = prepare_new_sig (opd); opd->only_newsig_seen = 1; return err; case GPGME_STATUS_GOODSIG: case GPGME_STATUS_EXPSIG: case GPGME_STATUS_EXPKEYSIG: case GPGME_STATUS_BADSIG: case GPGME_STATUS_ERRSIG: case GPGME_STATUS_REVKEYSIG: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); opd->only_newsig_seen = 0; return parse_new_sig (opd, code, args, ctx->protocol); case GPGME_STATUS_VALIDSIG: opd->only_newsig_seen = 0; return sig ? parse_valid_sig (sig, args, ctx->protocol) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_NODATA: opd->only_newsig_seen = 0; if (!sig) return gpg_error (GPG_ERR_NO_DATA); sig->status = gpg_error (GPG_ERR_NO_DATA); break; case GPGME_STATUS_UNEXPECTED: opd->only_newsig_seen = 0; if (!sig) return gpg_error (GPG_ERR_GENERAL); sig->status = gpg_error (GPG_ERR_NO_DATA); break; case GPGME_STATUS_NOTATION_NAME: case GPGME_STATUS_NOTATION_FLAGS: case GPGME_STATUS_NOTATION_DATA: case GPGME_STATUS_POLICY_URL: opd->only_newsig_seen = 0; return sig ? parse_notation (sig, code, args) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TRUST_UNDEFINED: case GPGME_STATUS_TRUST_NEVER: case GPGME_STATUS_TRUST_MARGINAL: case GPGME_STATUS_TRUST_FULLY: case GPGME_STATUS_TRUST_ULTIMATE: opd->only_newsig_seen = 0; return sig ? parse_trust (sig, code, args) : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_PKA_TRUST_BAD: case GPGME_STATUS_PKA_TRUST_GOOD: opd->only_newsig_seen = 0; /* Check that we only get one of these status codes per signature; if not the crypto backend misbehaves. */ if (!sig || sig->pka_trust || sig->pka_address) return trace_gpg_error (GPG_ERR_INV_ENGINE); sig->pka_trust = code == GPGME_STATUS_PKA_TRUST_GOOD? 2 : 1; end = strchr (args, ' '); if (end) *end = 0; sig->pka_address = strdup (args); break; case GPGME_STATUS_TOFU_USER: opd->only_newsig_seen = 0; return sig ? parse_tofu_user (sig, args) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TOFU_STATS: opd->only_newsig_seen = 0; return sig ? parse_tofu_stats (sig, args) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_TOFU_STATS_LONG: opd->only_newsig_seen = 0; return sig ? parse_tofu_stats_long (sig, args, ctx->raw_description) /* */ : trace_gpg_error (GPG_ERR_INV_ENGINE); case GPGME_STATUS_ERROR: opd->only_newsig_seen = 0; /* Some error stati are informational, so we don't return an error code if we are not ready to process this status. */ return parse_error (sig, args, !!sig ); case GPGME_STATUS_FAILURE: opd->failure_code = _gpgme_parse_failure (args); break; case GPGME_STATUS_EOF: if (sig && !opd->did_prepare_new_sig) calc_sig_summary (sig); if (opd->only_newsig_seen && sig) { gpgme_signature_t sig2; /* The last signature has no valid information - remove it from the list. */ assert (!sig->next); if (sig == opd->result.signatures) opd->result.signatures = NULL; else { for (sig2 = opd->result.signatures; sig2; sig2 = sig2->next) if (sig2->next == sig) { sig2->next = NULL; break; } } /* Note that there is no need to release the members of SIG because we won't be here if they have been set. */ free (sig); opd->current_sig = NULL; } opd->only_newsig_seen = 0; if (opd->failure_code) return opd->failure_code; break; case GPGME_STATUS_PLAINTEXT: if (++opd->plaintext_seen > 1) return gpg_error (GPG_ERR_BAD_DATA); err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; default: break; } return 0; }
/* Parse a TOFU_STATS line and store it in the last tofu info of SIG. * * TOFU_STATS <validity> <sign-count> 0 [<policy> [<tm1> <tm2>]] */ static gpgme_error_t parse_tofu_stats (gpgme_signature_t sig, char *args) { gpgme_error_t err; gpgme_tofu_info_t ti; char *field[6]; int nfields; unsigned long uval; if (!sig->tofu) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* No TOFU_USER seen. */ for (ti = sig->tofu; ti->next; ti = ti->next) ; if (ti->firstseen || ti->signcount || ti->validity || ti->policy) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Already seen. */ nfields = _gpgme_split_fields (args, field, DIM (field)); if (nfields < 3) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* Required args missing. */ /* Note that we allow a value of up to 7 which is what we can store * in the ti->validity. */ err = _gpgme_strtoul_field (field[0], &uval); if (err || uval > 7) return trace_gpg_error (GPG_ERR_INV_ENGINE); ti->validity = uval; /* Parse the sign-count. */ err = _gpgme_strtoul_field (field[1], &uval); if (err) return trace_gpg_error (GPG_ERR_INV_ENGINE); if (uval > USHRT_MAX) uval = USHRT_MAX; ti->signcount = uval; /* We skip the 0, which is RFU. */ if (nfields == 3) return 0; /* All mandatory fields parsed. */ /* Parse the policy. */ if (!strcmp (field[3], "none")) ti->policy = GPGME_TOFU_POLICY_NONE; else if (!strcmp (field[3], "auto")) ti->policy = GPGME_TOFU_POLICY_AUTO; else if (!strcmp (field[3], "good")) ti->policy = GPGME_TOFU_POLICY_GOOD; else if (!strcmp (field[3], "bad")) ti->policy = GPGME_TOFU_POLICY_BAD; else if (!strcmp (field[3], "ask")) ti->policy = GPGME_TOFU_POLICY_ASK; else /* "unknown" and invalid policy strings. */ ti->policy = GPGME_TOFU_POLICY_UNKNOWN; if (nfields == 4) return 0; /* No more optional fields. */ /* Parse first and last seen (none or both are required). */ if (nfields < 6) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* "tm2" missing. */ err = _gpgme_strtoul_field (field[4], &uval); if (err) return trace_gpg_error (GPG_ERR_INV_ENGINE); if (uval > UINT_MAX) uval = UINT_MAX; ti->firstseen = uval; err = _gpgme_strtoul_field (field[5], &uval); if (err) return trace_gpg_error (GPG_ERR_INV_ENGINE); if (uval > UINT_MAX) uval = UINT_MAX; ti->lastseen = uval; return 0; }
static gpgme_error_t parse_notation (gpgme_signature_t sig, gpgme_status_code_t code, char *args) { gpgme_error_t err; gpgme_sig_notation_t *lastp = &sig->notations; gpgme_sig_notation_t notation = sig->notations; char *p; if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) { p = strchr (args, ' '); if (p) *p = '\0'; /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->value) { lastp = ¬ation->next; notation = notation->next; } if (notation) /* There is another notation name without data for the previous one. The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); err = _gpgme_sig_notation_create (¬ation, NULL, 0, NULL, 0, 0); if (err) return err; if (code == GPGME_STATUS_NOTATION_NAME) { err = _gpgme_decode_percent_string (args, ¬ation->name, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->name_len = strlen (notation->name); /* Set default flags for use with older gpg versions which * do not emit a NOTATIONS_FLAG line. */ notation->flags = GPGME_SIG_NOTATION_HUMAN_READABLE; notation->human_readable = 1; } else { /* This is a policy URL. */ err = _gpgme_decode_percent_string (args, ¬ation->value, 0, 0); if (err) { _gpgme_sig_notation_free (notation); return err; } notation->value_len = strlen (notation->value); } *lastp = notation; } else if (code == GPGME_STATUS_NOTATION_FLAGS) { char *field[2]; while (notation && notation->next) { lastp = ¬ation->next; notation = notation->next; } if (!notation || !notation->name) { /* There are notation flags without a previous notation name. * The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); } if (_gpgme_split_fields (args, field, DIM (field)) < 2) { /* Required args missing. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); } notation->flags = 0; if (atoi (field[0])) { notation->flags |= GPGME_SIG_NOTATION_CRITICAL; notation->critical = 1; } if (atoi (field[1])) { notation->flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; notation->human_readable = 1; } } else if (code == GPGME_STATUS_NOTATION_DATA) { int len = strlen (args) + 1; char *dest; /* FIXME: We could keep a pointer to the last notation in the list. */ while (notation && notation->next) { lastp = ¬ation->next; notation = notation->next; } if (!notation || !notation->name) /* There is notation data without a previous notation name. The crypto backend misbehaves. */ return trace_gpg_error (GPG_ERR_INV_ENGINE); if (!notation->value) { dest = notation->value = malloc (len); if (!dest) return gpg_error_from_syserror (); } else { int cur_len = strlen (notation->value); dest = realloc (notation->value, len + strlen (notation->value)); if (!dest) return gpg_error_from_syserror (); notation->value = dest; dest += cur_len; } err = _gpgme_decode_percent_string (args, &dest, len, 0); if (err) return err; notation->value_len += strlen (dest); } else return trace_gpg_error (GPG_ERR_INV_ENGINE); return 0; }
static gpgme_error_t parse_valid_sig (gpgme_signature_t sig, char *args, gpgme_protocol_t protocol) { char *end = strchr (args, ' '); if (end) { *end = '\0'; end++; } if (!*args) /* We require at least the fingerprint. */ return gpg_error (GPG_ERR_GENERAL); if (sig->fpr) free (sig->fpr); sig->fpr = strdup (args); if (!sig->fpr) return gpg_error_from_syserror (); /* Skip the creation date. */ end = strchr (end, ' '); if (end) { char *tail; sig->timestamp = _gpgme_parse_timestamp (end, &tail); if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) return trace_gpg_error (GPG_ERR_INV_ENGINE); end = tail; sig->exp_timestamp = _gpgme_parse_timestamp (end, &tail); if (sig->exp_timestamp == -1 || end == tail || (*tail && *tail != ' ')) return trace_gpg_error (GPG_ERR_INV_ENGINE); end = tail; while (*end == ' ') end++; /* Skip the signature version. */ end = strchr (end, ' '); if (end) { while (*end == ' ') end++; /* Skip the reserved field. */ end = strchr (end, ' '); if (end) { /* Parse the pubkey algo. */ gpg_err_set_errno (0); sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol); if (errno || end == tail || *tail != ' ') return trace_gpg_error (GPG_ERR_INV_ENGINE); end = tail; while (*end == ' ') end++; if (*end) { /* Parse the hash algo. */ gpg_err_set_errno (0); sig->hash_algo = strtol (end, &tail, 0); if (errno || end == tail || *tail != ' ') return trace_gpg_error (GPG_ERR_INV_ENGINE); end = tail; } } } } return 0; }
static gpgme_error_t parse_new_sig (op_data_t opd, gpgme_status_code_t code, char *args, gpgme_protocol_t protocol) { gpgme_signature_t sig; char *end = strchr (args, ' '); char *tail; if (end) { *end = '\0'; end++; } if (!opd->did_prepare_new_sig) { gpg_error_t err; err = prepare_new_sig (opd); if (err) return err; } assert (opd->did_prepare_new_sig); opd->did_prepare_new_sig = 0; assert (opd->current_sig); sig = opd->current_sig; /* FIXME: We should set the source of the state. */ switch (code) { case GPGME_STATUS_GOODSIG: sig->status = gpg_error (GPG_ERR_NO_ERROR); break; case GPGME_STATUS_EXPSIG: sig->status = gpg_error (GPG_ERR_SIG_EXPIRED); break; case GPGME_STATUS_EXPKEYSIG: sig->status = gpg_error (GPG_ERR_KEY_EXPIRED); break; case GPGME_STATUS_BADSIG: sig->status = gpg_error (GPG_ERR_BAD_SIGNATURE); break; case GPGME_STATUS_REVKEYSIG: sig->status = gpg_error (GPG_ERR_CERT_REVOKED); break; case GPGME_STATUS_ERRSIG: /* Parse the pubkey algo. */ if (!end) goto parse_err_sig_fail; gpg_err_set_errno (0); sig->pubkey_algo = _gpgme_map_pk_algo (strtol (end, &tail, 0), protocol); if (errno || end == tail || *tail != ' ') goto parse_err_sig_fail; end = tail; while (*end == ' ') end++; /* Parse the hash algo. */ if (!*end) goto parse_err_sig_fail; gpg_err_set_errno (0); sig->hash_algo = strtol (end, &tail, 0); if (errno || end == tail || *tail != ' ') goto parse_err_sig_fail; end = tail; while (*end == ' ') end++; /* Skip the sig class. */ end = strchr (end, ' '); if (!end) goto parse_err_sig_fail; while (*end == ' ') end++; /* Parse the timestamp. */ sig->timestamp = _gpgme_parse_timestamp (end, &tail); if (sig->timestamp == -1 || end == tail || (*tail && *tail != ' ')) return trace_gpg_error (GPG_ERR_INV_ENGINE); end = tail; while (*end == ' ') end++; /* Parse the return code. */ if (end[0] && (!end[1] || end[1] == ' ')) { switch (end[0]) { case '4': sig->status = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); break; case '9': sig->status = gpg_error (GPG_ERR_NO_PUBKEY); break; default: sig->status = gpg_error (GPG_ERR_GENERAL); } } else goto parse_err_sig_fail; goto parse_err_sig_ok; parse_err_sig_fail: sig->status = gpg_error (GPG_ERR_GENERAL); parse_err_sig_ok: break; default: return gpg_error (GPG_ERR_GENERAL); } if (*args) { sig->fpr = strdup (args); if (!sig->fpr) return gpg_error_from_syserror (); } return 0; }
static gpgme_error_t gpgconf_config_load_cb2 (void *hook, char *line) { gpgme_error_t err; gpgme_conf_comp_t comp = hook; gpgme_conf_opt_t *opt_p = comp->_last_opt_p; gpgme_conf_opt_t opt; #define NR_FIELDS 16 char *field[NR_FIELDS]; int fields = 0; while (line && fields < NR_FIELDS) { field[fields++] = line; line = strchr (line, ':'); if (line) *(line++) = '\0'; } /* We require at least the first 10 fields. */ if (fields < 10) return trace_gpg_error (GPG_ERR_INV_ENGINE); opt = calloc (1, sizeof (*opt)); if (!opt) return gpg_error_from_syserror (); comp->_last_opt_p = &opt->next; *opt_p = opt; if (field[0][0]) { opt->name = strdup (field[0]); if (!opt->name) return gpg_error_from_syserror (); } opt->flags = strtoul (field[1], NULL, 0); opt->level = strtoul (field[2], NULL, 0); if (field[3][0]) { opt->description = strdup (field[3]); if (!opt->description) return gpg_error_from_syserror (); } opt->type = strtoul (field[4], NULL, 0); opt->alt_type = strtoul (field[5], NULL, 0); if (field[6][0]) { opt->argname = strdup (field[6]); if (!opt->argname) return gpg_error_from_syserror (); } if (opt->flags & GPGME_CONF_DEFAULT) { err = gpgconf_parse_option (opt, &opt->default_value, field[7]); if (err) return err; } else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0]) { opt->default_description = strdup (field[7]); if (!opt->default_description) return gpg_error_from_syserror (); } if (opt->flags & GPGME_CONF_NO_ARG_DESC) { opt->no_arg_description = strdup (field[8]); if (!opt->no_arg_description) return gpg_error_from_syserror (); } else { err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]); if (err) return err; } err = gpgconf_parse_option (opt, &opt->value, field[9]); if (err) return err; return 0; }
gpgme_error_t _gpgme_decrypt_status_handler (void *priv, gpgme_status_code_t code, char *args) { gpgme_ctx_t ctx = (gpgme_ctx_t) priv; gpgme_error_t err; void *hook; op_data_t opd; err = _gpgme_passphrase_status_handler (priv, code, args); if (err) return err; err = _gpgme_op_data_lookup (ctx, OPDATA_DECRYPT, &hook, -1, NULL); opd = hook; if (err) return err; switch (code) { case GPGME_STATUS_FAILURE: opd->failure_code = _gpgme_parse_failure (args); break; case GPGME_STATUS_EOF: /* FIXME: These error values should probably be attributed to the underlying crypto engine (as error source). */ if (opd->failed) return gpg_error (GPG_ERR_DECRYPT_FAILED); else if (!opd->okay) return gpg_error (GPG_ERR_NO_DATA); else if (opd->failure_code) return opd->failure_code; break; case GPGME_STATUS_DECRYPTION_INFO: /* Fixme: Provide a way to return the used symmetric algorithm. */ break; case GPGME_STATUS_DECRYPTION_OKAY: opd->okay = 1; break; case GPGME_STATUS_DECRYPTION_FAILED: opd->failed = 1; break; case GPGME_STATUS_ERROR: /* Note that this is an informational status code which should not lead to an error return unless it is something not related to the backend. */ { const char d_alg[] = "decrypt.algorithm"; const char k_alg[] = "decrypt.keyusage"; if (!strncmp (args, d_alg, sizeof (d_alg) - 1)) { args += sizeof (d_alg) - 1; while (*args == ' ') args++; if (gpg_err_code (atoi (args)) == GPG_ERR_UNSUPPORTED_ALGORITHM) { char *end; while (*args && *args != ' ') args++; while (*args == ' ') args++; end = strchr (args, ' '); if (end) *end = '\0'; if (!(*args == '?' && *(args + 1) == '\0')) { opd->result.unsupported_algorithm = strdup (args); if (!opd->result.unsupported_algorithm) return gpg_error_from_syserror (); } } } else if (!strncmp (args, k_alg, sizeof (k_alg) - 1)) { args += sizeof (k_alg) - 1; while (*args == ' ') args++; if (gpg_err_code (atoi (args)) == GPG_ERR_WRONG_KEY_USAGE) opd->result.wrong_key_usage = 1; } } break; case GPGME_STATUS_ENC_TO: err = parse_enc_to (args, opd->last_recipient_p, ctx->protocol); if (err) return err; opd->last_recipient_p = &(*opd->last_recipient_p)->next; break; case GPGME_STATUS_NO_SECKEY: { gpgme_recipient_t rec = opd->result.recipients; while (rec) { if (!strcmp (rec->keyid, args)) { rec->status = gpg_error (GPG_ERR_NO_SECKEY); break; } rec = rec->next; } /* FIXME: Is this ok? */ if (!rec) return trace_gpg_error (GPG_ERR_INV_ENGINE); } break; case GPGME_STATUS_PLAINTEXT: err = _gpgme_parse_plaintext (args, &opd->result.file_name); if (err) return err; break; case GPGME_STATUS_INQUIRE_MAXLEN: if (ctx->status_cb) { err = ctx->status_cb (ctx->status_cb_value, "INQUIRE_MAXLEN", args); if (err) return err; } break; default: break; } return 0; }
/* Parse a notation or policy URL subpacket. If the packet type is not known, return no error but NULL in NOTATION. */ gpgme_error_t _gpgme_parse_notation (gpgme_sig_notation_t *notationp, int type, int pkflags, int len, char *data) { gpgme_error_t err; char *name = NULL; int name_len = 0; char *value = NULL; int value_len = 0; gpgme_sig_notation_flags_t flags = 0; char *decoded_data; unsigned char *bdata; /* Type 20: Notation data. */ /* Type 26: Policy URL. */ if (type != 20 && type != 26) { *notationp = NULL; return 0; } /* A few simple sanity checks. */ if (len > strlen (data)) return trace_gpg_error (GPG_ERR_INV_ENGINE); /* See below for the format of a notation subpacket. It has at least four octets of flags and two times two octets of length information. */ if (type == 20 && len < 4 + 2 + 2) return trace_gpg_error (GPG_ERR_INV_ENGINE); err = _gpgme_decode_percent_string (data, &decoded_data, 0, 1); if (err) return err; bdata = (unsigned char *) decoded_data; /* Flags common to notation data and policy URL. */ if (pkflags & GNUPG_SPK_CRITICAL) flags |= GPGME_SIG_NOTATION_CRITICAL; /* This information is relevant in parsing multi-octet numbers below: 3.1. Scalar numbers Scalar numbers are unsigned, and are always stored in big-endian format. Using n[k] to refer to the kth octet being interpreted, the value of a two-octet scalar is ((n[0] << 8) + n[1]). The value of a four-octet scalar is ((n[0] << 24) + (n[1] << 16) + (n[2] << 8) + n[3]). From RFC2440: OpenPGP Message Format. Copyright (C) The Internet Society (1998). All Rights Reserved. */ #define RFC2440_GET_WORD(chr) ((((int)((unsigned char *)(chr))[0]) << 8) \ + ((int)((unsigned char *)(chr))[1])) if (type == 20) { /* 5.2.3.15. Notation Data (4 octets of flags, 2 octets of name length (M), 2 octets of value length (N), M octets of name data, N octets of value data) [...] The "flags" field holds four octets of flags. All undefined flags MUST be zero. Defined flags are: First octet: 0x80 = human-readable. [...] Other octets: none. From RFC2440: OpenPGP Message Format. Copyright (C) The Internet Society (1998). All Rights Reserved. */ int chr; /* First octet of flags. */ #define RFC2440_SPK20_FLAG1_HUMAN_READABLE 0x80 chr = *bdata; bdata++; if (chr & RFC2440_SPK20_FLAG1_HUMAN_READABLE) flags |= GPGME_SIG_NOTATION_HUMAN_READABLE; /* The second, third and four octet of flags are unused. */ bdata++; bdata++; bdata++; name_len = RFC2440_GET_WORD (bdata); bdata += 2; value_len = RFC2440_GET_WORD (bdata); bdata += 2; /* Small sanity check. */ if (4 + 2 + 2 + name_len + value_len > len) { free (decoded_data); return trace_gpg_error (GPG_ERR_INV_ENGINE); } name = (char *) bdata; bdata += name_len; value = (char *) bdata; } else { /* Type is 26. */ /* NAME is NULL, name_len is 0. */ value = (char *) bdata; value_len = strlen (value); } err = _gpgme_sig_notation_create (notationp, name, name_len, value, value_len, flags); free (decoded_data); return err; }
static gpgme_error_t parse_import (char *args, gpgme_import_status_t *import_status, int problem) { gpgme_import_status_t import; char *tail; long int nr; import = malloc (sizeof (*import)); if (!import) return gpg_error_from_syserror (); import->next = NULL; gpg_err_set_errno (0); nr = strtol (args, &tail, 0); if (errno || args == tail || *tail != ' ') { /* The crypto backend does not behave. */ free (import); return trace_gpg_error (GPG_ERR_INV_ENGINE); } args = tail; if (problem) { switch (nr) { case 0: case 4: default: import->result = gpg_error (GPG_ERR_GENERAL); break; case 1: import->result = gpg_error (GPG_ERR_BAD_CERT); break; case 2: import->result = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); break; case 3: import->result = gpg_error (GPG_ERR_BAD_CERT_CHAIN); break; } import->status = 0; } else { import->result = gpg_error (GPG_ERR_NO_ERROR); import->status = nr; } while (*args == ' ') args++; tail = strchr (args, ' '); if (tail) *tail = '\0'; import->fpr = strdup (args); if (!import->fpr) { free (import); return gpg_error_from_syserror (); } *import_status = import; return 0; }
/* Parse the INV_RECP or INV-SNDR status line in ARGS and return the result in KEY. */ gpgme_error_t _gpgme_parse_inv_recp (char *args, gpgme_invalid_key_t *key) { gpgme_invalid_key_t inv_key; char *tail; long int reason; inv_key = malloc (sizeof (*inv_key)); if (!inv_key) return gpg_error_from_syserror (); inv_key->next = NULL; gpg_err_set_errno (0); reason = strtol (args, &tail, 0); if (errno || args == tail || (*tail && *tail != ' ')) { /* The crypto backend does not behave. */ free (inv_key); return trace_gpg_error (GPG_ERR_INV_ENGINE); } switch (reason) { default: case 0: inv_key->reason = gpg_error (GPG_ERR_GENERAL); break; case 1: inv_key->reason = gpg_error (GPG_ERR_NO_PUBKEY); break; case 2: inv_key->reason = gpg_error (GPG_ERR_AMBIGUOUS_NAME); break; case 3: inv_key->reason = gpg_error (GPG_ERR_WRONG_KEY_USAGE); break; case 4: inv_key->reason = gpg_error (GPG_ERR_CERT_REVOKED); break; case 5: inv_key->reason = gpg_error (GPG_ERR_CERT_EXPIRED); break; case 6: inv_key->reason = gpg_error (GPG_ERR_NO_CRL_KNOWN); break; case 7: inv_key->reason = gpg_error (GPG_ERR_CRL_TOO_OLD); break; case 8: inv_key->reason = gpg_error (GPG_ERR_NO_POLICY_MATCH); break; case 9: inv_key->reason = gpg_error (GPG_ERR_NO_SECKEY); break; case 10: inv_key->reason = gpg_error (GPG_ERR_PUBKEY_NOT_TRUSTED); break; case 11: inv_key->reason = gpg_error (GPG_ERR_MISSING_CERT); break; case 12: inv_key->reason = gpg_error (GPG_ERR_MISSING_ISSUER_CERT); break; case 13: inv_key->reason = gpg_error (252); /*GPG_ERR_KEY_DISABLED*/ break; case 14: inv_key->reason = gpg_error (GPG_ERR_INV_USER_ID); break; } while (*tail && *tail == ' ') tail++; if (*tail) { inv_key->fpr = strdup (tail); if (!inv_key->fpr) { free (inv_key); return gpg_error_from_syserror (); } } else inv_key->fpr = NULL; *key = inv_key; return 0; }