e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen/*
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * OTP extended response parser.
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * Copyright (c) 2006 Andrey Panin <pazke@donpac.ru>
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen * This software is released under the MIT license.
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen */
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "lib.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "buffer.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "str.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "strfuncs.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "hex-binary.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include "otp.h"
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#include <ctype.h>
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#define IS_LWS(c) ((c) == ' ' || (c) == '\t')
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenstatic inline const char *otp_skip_lws(const char *data)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen while (*data != '\0' && IS_LWS(*data))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen data++;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainenstatic inline bool otp_check_tail(const char *data)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen data = otp_skip_lws(data);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return *data != 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_read_hex(const char *data, const char **endptr, unsigned char *hash)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen string_t *str;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen buffer_t buf;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned int i = 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (data == NULL)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen str = t_str_new(18);
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_data(&buf, hash, OTP_HASH_SIZE);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen while (*data != '\0') {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen char c = *data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (i_isxdigit(c)) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen str_append_c(str, c);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (++i == OTP_HASH_SIZE * 2) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen data++;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen break;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen } else if (!IS_LWS(c)) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *endptr = data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen data++;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *endptr = data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (i < OTP_HASH_SIZE * 2)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen return hex_to_binary(str_c(str), &buf);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen#define add_word() do { \
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen tmp = otp_lookup_word(str_c(word)); \
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen buffer_append(&buf, &tmp, sizeof(tmp)); \
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen count++; \
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen} while (0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_read_words(const char *data, const char **endptr, unsigned char *hash)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen bool space = FALSE;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned int len = 0, count = 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned int parity = 0, bits[OTP_WORDS_NUMBER], tmp;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen string_t *word;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen buffer_t buf;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (data == NULL)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen word = t_str_new(8);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen data = otp_skip_lws(data);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen buffer_create_from_data(&buf, bits, sizeof(bits));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen for (; *data != '\0' && (count < OTP_WORDS_NUMBER); data++) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen char c = *data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (space) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (IS_LWS(c))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen continue;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen else if (i_isalpha(c)) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen str_append_c(word, c);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen space = FALSE;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen len = 1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen continue;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen } else {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (i_isalpha(c)) {
d19412e30b27e413f99cbedab86c9f9396741638Timo Sirainen if (++len > OTP_MAX_WORD_LEN) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen count = 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen break;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen str_append_c(word, c);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen continue;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen } else if (IS_LWS(c)) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen add_word();
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen str_truncate(word, 0);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen space = TRUE;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen continue;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen break;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if ((str_len(word) > 0) && (count == OTP_WORDS_NUMBER - 1))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen add_word();
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if (endptr != NULL)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *endptr = data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (count < OTP_WORDS_NUMBER)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[0] = bits[0] >> 3;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[1] = ((bits[0] & 7) << 5) | (bits[1] >> 6);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[2] = ((bits[1] & 0x3f) << 2) | (bits[2] >> 9);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[3] = (bits[2] >> 1) & 0xff;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[4] = ((bits[2] & 3) << 7) | (bits[3] >> 4);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[5] = ((bits[3] & 15) << 4) | (bits[4] >> 7);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[6] = ((bits[4] & 0x7f) << 1) | (bits[5] >> 10);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen hash[7] = (bits[5] >> 2) & 0xff;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen parity = bits[5] & 3;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return otp_parity(hash) != parity ? 1 : 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_read_new_params(const char *data, const char **endptr,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen struct otp_state *state)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const char *p, *s;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned int i = 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen int algo;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen s = p = data;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen while ((*p != 0) && !IS_LWS(*p)) p++;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (*p == 0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen algo = digest_find(t_strdup_until(s, p++));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (algo < 0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -2;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen state->algo = algo;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen s = p;
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_parse_int(s, &state->seq, &p) < 0 || !IS_LWS(*p))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -3;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen p++;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen while (i_isalnum(*p) && (i < OTP_MAX_SEED_LEN))
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen state->seed[i++] = i_tolower(*p++);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen state->seed[i] = 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *endptr = p;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_parse_response(const char *data, unsigned char *hash, bool hex)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const char *end;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen int ret = hex ? otp_read_hex(data, &end, hash) :
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen otp_read_words(data, &end, hash);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (ret < 0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return ret;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
f0339f522dc9c8e2e8a29ef9a3f937c431c6bd1bTimo Sirainen return otp_check_tail(end) ? 1 : 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_parse_init_response(const char *data, struct otp_state *new_state,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen unsigned char *hash, bool hex, const char **error)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const char *end;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen int ret = hex ? otp_read_hex(data, &end, hash) :
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen otp_read_words(data, &end, hash);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (ret < 0) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "invalid current OTP";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return ret;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen end = otp_skip_lws(end);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (*end++ != ':') {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "missing colon";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ret = otp_read_new_params(end, &end, new_state);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (ret < 0) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "invalid OTP parameters";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen end = otp_skip_lws(end);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (*end++ != ':') {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "missing colon";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ret = hex ? otp_read_hex(end, &end, new_state->hash) :
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen otp_read_words(end, &end, new_state->hash);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (ret < 0) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "invalid new OTP";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if (otp_check_tail(end)) {
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen *error = "trailing garbage found";
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen }
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return 0;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenint otp_parse_dbentry(const char *text, struct otp_state *state)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen const char *end;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen int ret;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen ret = otp_read_new_params(text, &end, state);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (ret != 0)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return ret;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen if (*end++ != ' ')
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return -1;
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen return otp_read_hex(end, &end, state->hash);
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainenconst char *otp_print_dbentry(const struct otp_state *state)
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen{
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen return t_strdup_printf("%s %d %s %s", digest_name(state->algo),
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen state->seq, state->seed,
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen binary_to_hex(state->hash, 8));
e9e2d23e1ea5a149a7d8828d2a45b9f2313c3785Timo Sirainen}