46 for (
int i = 0; i < 32; i++) {
47 if (key->
key[i] != 0) {
88 for (
size_t i = 0; i < key_size; i++) {
111 if (!key || !is_expired) {
153 if (strncmp(key_text,
"ssh-ed25519 ", 12) != 0) {
159 const char *base64_start = key_text + 12;
160 while (*base64_start ==
' ' || *base64_start ==
'\t') {
164 if (*base64_start ==
'\0' || *base64_start ==
'\n' || *base64_start ==
'\r') {
183 if (strncmp(key_text,
"-----BEGIN PGP", 14) != 0) {
189 if (strstr(key_text,
"-----END PGP") == NULL) {
196 bool has_version_header = (strstr(key_text,
"Version:") != NULL);
197 bool has_charset_header = (strstr(key_text,
"Charset:") != NULL || strstr(key_text,
"Version:") != NULL);
199 if (!has_version_header && !has_charset_header) {
201 log_warn(
"GPG armor missing version/charset headers - key might be incomplete");
205 const char *start_pos = strstr(key_text,
"\n\n");
206 const char *end_pos = strstr(key_text,
"\n-----END");
207 if (start_pos && end_pos && start_pos < end_pos) {
209 ptrdiff_t diff = end_pos - start_pos - 2;
226 size_t hex_len = strlen(key_hex);
233 for (
size_t i = 0; i < hex_len; i++) {
234 if (!isxdigit(key_hex[i])) {
248 if (!key || !is_weak) {
258 for (
int i = 0; i < 32; i++) {
259 if (key->
key[i] != 0xFF) {
273 bool byte_seen[256] = {0};
274 int unique_bytes = 0;
275 for (
int i = 0; i < 32; i++) {
277 if (!byte_seen[byte_val]) {
278 byte_seen[byte_val] =
true;
285 if (unique_bytes < 8) {
305 if (stat(key_path, &st) != 0) {
321 if (!key || !has_weak_patterns) {
326 *has_weak_patterns =
false;
329 bool is_sequential =
true;
330 for (
int i = 1; i < 32; i++) {
331 if (key->
key[i] != key->
key[i - 1] + 1) {
332 is_sequential =
false;
338 *has_weak_patterns =
true;
344 const uint8_t weak_bytes[] = {0x00, 0xFF, 0xAA, 0x55, 0x11, 0x22, 0x33, 0x44,
345 0x66, 0x77, 0x88, 0x99, 0xBB, 0xCC, 0xDD, 0xEE};
346 for (
size_t pattern_idx = 0; pattern_idx <
sizeof(weak_bytes); pattern_idx++) {
347 uint8_t pattern_byte = weak_bytes[pattern_idx];
348 bool is_repeated =
true;
349 for (
size_t j = 0; j < 32; j++) {
351 if (key->
key[j] != pattern_byte) {
357 *has_weak_patterns =
true;
364 bool byte_appeared[256] = {0};
365 int unique_values = 0;
366 for (
size_t i = 0; i < 32; i++) {
367 if (!byte_appeared[key->
key[i]]) {
368 byte_appeared[key->
key[i]] =
true;
374 if (unique_values <= 2) {
375 bool is_alternating =
true;
376 for (
size_t i = 1; i < 32; i++) {
380 if (key->
key[i] == key->
key[i - 1] || (i >= 2 && key->
key[i] != key->
key[i - 2])) {
381 is_alternating =
false;
385 if (is_alternating) {
386 *has_weak_patterns =
true;
395 bool all_words_same =
true;
396 for (
size_t i = 1; i < 8; i++) {
397 if (words[i] != words[0]) {
398 all_words_same =
false;
402 if (all_words_same) {
403 *has_weak_patterns =
true;
415 if (!key1 || !key2 || !are_equal) {
428 if (sodium_memcmp(key1->
key, key2->
key, 32) == 0) {
437 if (!key || !fingerprint || !matches) {
448 return fingerprint_result;
452 size_t compare_len = (fingerprint_len < 32) ? fingerprint_len : 32;
453 if (sodium_memcmp(key_fingerprint, fingerprint, compare_len) == 0) {
461 if (!key || !fingerprint_out) {
466 if (fingerprint_size < 32) {
472 if (crypto_hash_sha256(fingerprint_out, key->
key, 32) != 0) {
⚠️‼️ Error and/or exit() when things go bad.
#define SSH_KEY_PERMISSIONS_MASK
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
asciichat_error_t check_key_expiry(const public_key_t *key, bool *is_expired)
Check if a key is expired.
asciichat_error_t validate_gpg_key_format(const char *key_text)
Validate GPG key format and structure.
asciichat_error_t validate_ssh_key_format(const char *key_text)
Validate SSH key format.
asciichat_error_t validate_key_security(const char *key_path)
Validate key permissions and security.
asciichat_error_t validate_private_key(const private_key_t *key)
Validate a private key structure.
asciichat_error_t validate_key_permissions(const char *key_path)
Validate key file permissions.
asciichat_error_t validate_public_key(const public_key_t *key)
Validate a public key structure.
asciichat_error_t check_key_fingerprint(const public_key_t *key, const uint8_t *fingerprint, size_t fingerprint_len, bool *matches)
Check if key matches a fingerprint.
asciichat_error_t check_key_patterns(const public_key_t *key, bool *has_weak_patterns)
Check for key reuse or weak patterns.
asciichat_error_t check_key_strength(const public_key_t *key, bool *is_weak)
Check if key has weak parameters.
asciichat_error_t validate_x25519_key_format(const char *key_hex)
Validate X25519 key format.
union private_key_t::@1 key
asciichat_error_t compare_public_keys(const public_key_t *key1, const public_key_t *key2, bool *are_equal)
Compare two public keys for equality.
asciichat_error_t generate_key_fingerprint(const public_key_t *key, uint8_t *fingerprint_out, size_t fingerprint_size)
Generate key fingerprint.
#define log_warn(...)
Log a WARN message.
Private key structure (for server –ssh-key)