forked from cisco/hash-sigs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhss_verify.c
More file actions
156 lines (139 loc) · 5.61 KB
/
hss_verify.c
File metadata and controls
156 lines (139 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* This is the code that implements the hierarchical part of the LMS hash
* based signatures
*/
#include <string.h>
#include "common_defs.h"
#include "hss_verify.h"
#include "lm_verify.h"
#include "lm_common.h"
#include "lm_ots_verify.h"
#include "hash.h"
#include "endian.h"
#include "hss_thread.h"
#include "hss_internal.h"
#include "hss.h"
/* The HSS public key consists of: */
/* Number of levels (1-8) (4 bytes) */
/* The top level LM public key */
/* The HSS signature consists of: */
/* A word giving the number of levels - 1 == L-1 */
/* L-1 iterations of (i = 1..L-1): */
/* - LMS Signature of public key i (signed by the pub key of level i-1) */
/* - LMS Public key (of level i) */
/* - LMS Signature of the message, signed by the bottomost pub key */
/* This is the routine that runs on a thread to validate an LMS signature */
void validate_internal_sig(const void *data,
struct thread_collection *col) {
const struct verify_detail *d = data;
bool success = lm_validate_signature(d->public_key,
d->message, d->message_len, false,
d->signature, d->signature_len);
if (!success) {
/* Drat, it failed; call the failure in */
hss_thread_before_write(col);
*d->got_error = hss_error_bad_signature;
hss_thread_after_write(col);
}
}
/*
* Validate an HSS signature, using a public key. Parameters:
* public_key - pointer to the public key
* message - the mmessage that was supposedly signed
* message_len - the size of the message
* siganture - the signature we're checking
* signature_len - the length of the signature
*
* This returns true if everything checks out and the signature verifies
* false on error (whether the error is because thee signature didn't verify,
* or we hit some sort of error on the way)
*/
bool hss_validate_signature(
const unsigned char *public_key,
const void *message, size_t message_len,
const unsigned char *signature, size_t signature_len,
struct hss_extra_info *info) {
struct hss_extra_info temp_info = { 0 };
if (!info) info = &temp_info;
unsigned i;
/* Get the number of levels the signature claims */
if (signature_len < 4) {
info->error_code = hss_error_bad_signature;
return false;
}
uint_fast32_t levels = get_bigendian( signature, 4 ) + 1;
/* +1 because what's in the signature is levels-1 */
signature += 4; signature_len -= 4;
if (levels < MIN_HSS_LEVELS || levels > MAX_HSS_LEVELS ||
levels != get_bigendian( public_key, 4 )) {
info->error_code = hss_error_bad_signature;
return false;
}
uint_fast32_t pub_levels = get_bigendian( public_key, 4 );
if (levels != pub_levels) {
/* Signature and public key don't agree */
info->error_code = hss_error_bad_signature;
return false;
}
public_key += 4;
struct thread_collection *col = hss_thread_init(info->num_threads);
enum hss_error_code got_error = hss_error_none;
struct verify_detail detail;
detail.got_error = &got_error;
/* Scan through the signature, kicking off the tasks to validate it */
/* as we go */
for (i=0; i<levels-1; i++) {
/* The next thing is the signature of this public key */
param_set_t lm_type = get_bigendian( public_key, 4 );
param_set_t lm_ots_type = get_bigendian( public_key+4, 4 );
unsigned l_siglen = lm_get_signature_len(lm_type, lm_ots_type);
if (l_siglen == 0 || l_siglen > signature_len) {
info->error_code = hss_error_bad_signature;
goto failed;
}
const unsigned char *l_sig = signature;
signature += l_siglen; signature_len -= l_siglen;
/* The next thing is the next level public key (which we need */
/* to validate) */
if (signature_len < 4) {
info->error_code = hss_error_bad_signature;
goto failed;
}
lm_type = get_bigendian( signature, 4 );
unsigned l_pubkeylen = lm_get_public_key_len(lm_type);
if (l_pubkeylen == 0 || l_pubkeylen > signature_len) {
info->error_code = hss_error_bad_signature;
goto failed;
}
const unsigned char *l_pubkey = signature;
signature += l_pubkeylen; signature_len -= l_pubkeylen;
/* Validate the signature of this level's public key */
detail.public_key = public_key;
detail.message = l_pubkey;
detail.message_len = l_pubkeylen;
detail.signature = l_sig;
detail.signature_len = l_siglen;
hss_thread_issue_work( col, validate_internal_sig,
&detail, sizeof detail );
/* We validated this level's public key (or, at least, scheduled */
/* it, if it turns out not to validate, we'll catch it below), use */
/* it to validate the next level */
public_key = l_pubkey;
}
/* Ok, we're at the bottom level, issue the final verification */
detail.public_key = public_key;
detail.message = message;
detail.message_len = message_len;
detail.signature = signature;
detail.signature_len = signature_len;
hss_thread_issue_work( col, validate_internal_sig, &detail, sizeof detail );
/* Wait for all the threads to complete */
hss_thread_done(col);
/* It succeeded if none of the threads reported an error */
if (got_error == hss_error_none) return true;
info->error_code = got_error;
return false;
failed: /* If we get an intermediate failure */
hss_thread_done(col);
return false;
}