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
// Copyright (c) 2019, Nick Stevens <nick@bitcurry.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use pem::PemError;
use simple_asn1::{ASN1DecodeErr, ASN1EncodeErr};
use std::io;
use thiserror::Error;

/// Saltlick errors.
#[derive(Clone, Debug, Error, Hash, Eq, PartialEq)]
pub enum SaltlickError {
    #[error("Magic value incorrect - is this a saltlick file?")]
    BadMagic,
    #[error("Failed to decrypt - stream is corrupt.")]
    DecryptionFailure,
    #[error("Stream is finalized, no more data may be written.")]
    Finalized,
    #[error("Stream ended before Final tag receive, file is incomplete!")]
    Incomplete,
    #[error("Key is the incorrect length.")]
    IncorrectKeyLength,
    #[error("Key file is invalid, must be PEM encoded ASN.1")]
    InvalidKeyFormat,
    #[error("Provided public key does not match file public key.")]
    PublicKeyMismatch,
    #[error("Unable to find secret key for file.")]
    SecretKeyNotFound,
    #[error("The state machine was called having previously returned an error.")]
    StateMachineErrored,
    #[error("Stream failed to start.")]
    StreamStartFailure,
    #[error("Key algorithm is unknown or unsupported.")]
    UnsupportedKeyAlgorithm,
    #[error("Version is unknown or unsupported.")]
    UnsupportedVersion,
}

impl From<PemError> for SaltlickError {
    fn from(_: PemError) -> SaltlickError {
        SaltlickError::InvalidKeyFormat
    }
}

impl From<ASN1EncodeErr> for SaltlickError {
    fn from(_: ASN1EncodeErr) -> SaltlickError {
        SaltlickError::InvalidKeyFormat
    }
}

impl From<ASN1DecodeErr> for SaltlickError {
    fn from(_: ASN1DecodeErr) -> SaltlickError {
        SaltlickError::InvalidKeyFormat
    }
}

impl From<SaltlickError> for io::Error {
    fn from(e: SaltlickError) -> io::Error {
        io::Error::new(io::ErrorKind::Other, e)
    }
}

/// Errors when loading keys directly from a file.
///
/// Errors possible when keys are loaded directly from files. Note that this is
/// not part of the normal `SaltlickError` because `std::io::Error` does not
/// implement `Clone`, `Hash`, or `Eq`.
#[derive(Debug, Error)]
pub enum SaltlickKeyIoError {
    #[error("key file I/O error: {0}")]
    IoError(#[from] io::Error),
    #[error("key file parse error: {0}")]
    SaltlickError(#[from] SaltlickError),
}

#[cfg(test)]
mod tests {
    use super::SaltlickError;
    use pem::PemError;
    use simple_asn1::{ASN1DecodeErr, ASN1EncodeErr};

    #[test]
    fn from_conversions_test() {
        assert_eq!(
            SaltlickError::InvalidKeyFormat,
            SaltlickError::from(PemError::MissingData),
        );
        assert_eq!(
            SaltlickError::InvalidKeyFormat,
            SaltlickError::from(ASN1EncodeErr::ObjectIdentHasTooFewFields),
        );
        assert_eq!(
            SaltlickError::InvalidKeyFormat,
            SaltlickError::from(ASN1DecodeErr::EmptyBuffer),
        );
    }
}