Certificate error codes

This commit is contained in:
Steven Fackler 2013-11-16 21:09:45 -08:00
parent f8be641536
commit 0b287710c4
3 changed files with 181 additions and 3 deletions

66
ffi.rs
View File

@ -2,7 +2,6 @@
use std::libc::{c_int, c_void, c_long, c_ulong, c_char};
// openssl/ssl.h
pub type SSL_CTX = c_void;
pub type SSL_METHOD = c_void;
pub type SSL = c_void;
@ -36,6 +35,70 @@ pub static SSL_ERROR_WANT_ACCEPT: c_int = 8;
pub static SSL_VERIFY_NONE: c_int = 0;
pub static SSL_VERIFY_PEER: c_int = 1;
pub static X509_V_OK: c_int = 0;
/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */
pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2;
pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3;
pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4;
pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5;
pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6;
pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7;
pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8;
pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9;
pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10;
pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11;
pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12;
pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13;
pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14;
pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15;
pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16;
pub static X509_V_ERR_OUT_OF_MEM: c_int = 17;
pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18;
pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19;
pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20;
pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21;
pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22;
pub static X509_V_ERR_CERT_REVOKED: c_int = 23;
pub static X509_V_ERR_INVALID_CA: c_int = 24;
pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25;
pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26;
pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27;
pub static X509_V_ERR_CERT_REJECTED: c_int = 28;
/* These are 'informational' when looking for issuer cert */
pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29;
pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30;
pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31;
pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32;
pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33;
pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34;
pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35;
pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36;
pub static X509_V_ERR_INVALID_NON_CA: c_int = 37;
pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38;
pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39;
pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40;
pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41;
pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42;
pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43;
pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44;
pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45;
pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46;
pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47;
pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48;
pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49;
pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51;
pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52;
pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53;
pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54;
/* The application is not happy */
pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50;
#[link_args = "-lssl -lcrypto"]
extern "C" {
pub fn ERR_get_error() -> c_ulong;
@ -64,6 +127,7 @@ extern "C" {
pub fn X509_STORE_CTX_get_ex_data(ctx: *X509_STORE_CTX, idx: c_int)
-> *c_void;
pub fn X509_STORE_CTX_get_current_cert(ct: *X509_STORE_CTX) -> *X509;
pub fn X509_STORE_CTX_get_error(ctx: *X509_STORE_CTX) -> c_int;
pub fn SSL_new(ctx: *SSL_CTX) -> *SSL;
pub fn SSL_free(ssl: *SSL);

88
lib.rs
View File

@ -1,4 +1,4 @@
#[feature(struct_variant)];
#[feature(struct_variant, macro_rules)];
// Needed for rustdoc-ng
#[link(name="rust-ssl", vers="0.1",
@ -15,6 +15,7 @@ use std::io::{Stream, Reader, Writer, Decorator};
use std::vec;
use self::error::{SslError, SslSessionClosed, StreamEof};
use self::hack::X509ValidationError;
pub mod error;
@ -159,6 +160,11 @@ pub struct X509StoreContext {
}
impl X509StoreContext {
pub fn get_error(&self) -> Option<X509ValidationError> {
let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) };
X509ValidationError::from_raw(err)
}
pub fn get_current_cert(&self) -> Option<X509> {
let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) };
@ -175,6 +181,86 @@ pub struct X509 {
priv x509: *ffi::X509
}
macro_rules! make_validation_error(
($ok_val:ident, $($name:ident = $val:ident,)+) => (
pub mod hack {
use std::libc::c_int;
pub enum X509ValidationError {
$($name,)+
X509UnknownError(c_int)
}
impl X509ValidationError {
#[doc(hidden)]
pub fn from_raw(err: c_int) -> Option<X509ValidationError> {
match err {
super::ffi::$ok_val => None,
$(super::ffi::$val => Some($name),)+
err => Some(X509UnknownError(err))
}
}
}
}
)
)
make_validation_error!(X509_V_OK,
X509UnableToGetIssuerCert = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT,
X509UnableToGetCrl = X509_V_ERR_UNABLE_TO_GET_CRL,
X509UnableToDecryptCertSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE,
X509UnableToDecryptCrlSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE,
X509UnableToDecodeIssuerPublicKey = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY,
X509CertSignatureFailure = X509_V_ERR_CERT_SIGNATURE_FAILURE,
X509CrlSignatureFailure = X509_V_ERR_CRL_SIGNATURE_FAILURE,
X509CertNotYetValid = X509_V_ERR_CERT_NOT_YET_VALID,
X509CertHasExpired = X509_V_ERR_CERT_HAS_EXPIRED,
X509CrlNotYetValid = X509_V_ERR_CRL_NOT_YET_VALID,
X509CrlHasExpired = X509_V_ERR_CRL_HAS_EXPIRED,
X509ErrorInCertNotBeforeField = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD,
X509ErrorInCertNotAfterField = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD,
X509ErrorInCrlLastUpdateField = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD,
X509ErrorInCrlNextUpdateField = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD,
X509OutOfMem = X509_V_ERR_OUT_OF_MEM,
X509DepthZeroSelfSignedCert = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT,
X509SelfSignedCertInChain = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN,
X509UnableToGetIssuerCertLocally = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY,
X509UnableToVerifyLeafSignature = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE,
X509CertChainTooLong = X509_V_ERR_CERT_CHAIN_TOO_LONG,
X509CertRevoked = X509_V_ERR_CERT_REVOKED,
X509InvalidCA = X509_V_ERR_INVALID_CA,
X509PathLengthExceeded = X509_V_ERR_PATH_LENGTH_EXCEEDED,
X509InvalidPurpose = X509_V_ERR_INVALID_PURPOSE,
X509CertUntrusted = X509_V_ERR_CERT_UNTRUSTED,
X509CertRejected = X509_V_ERR_CERT_REJECTED,
X509SubjectIssuerMismatch = X509_V_ERR_SUBJECT_ISSUER_MISMATCH,
X509AkidSkidMismatch = X509_V_ERR_AKID_SKID_MISMATCH,
X509AkidIssuerSerialMismatch = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH,
X509KeyusageNoCertsign = X509_V_ERR_KEYUSAGE_NO_CERTSIGN,
X509UnableToGetCrlIssuer = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER,
X509UnhandledCriticalExtension = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION,
X509KeyusageNoCrlSign = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN,
X509UnhandledCriticalCrlExtension = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION,
X509InvalidNonCA = X509_V_ERR_INVALID_NON_CA,
X509ProxyPathLengthExceeded = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED,
X509KeyusageNoDigitalSignature = X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE,
X509ProxyCertificatesNotAllowed = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED,
X509InvalidExtension = X509_V_ERR_INVALID_EXTENSION,
X509InavlidPolicyExtension = X509_V_ERR_INVALID_POLICY_EXTENSION,
X509NoExplicitPolicy = X509_V_ERR_NO_EXPLICIT_POLICY,
X509DifferentCrlScope = X509_V_ERR_DIFFERENT_CRL_SCOPE,
X509UnsupportedExtensionFeature = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE,
X509UnnestedResource = X509_V_ERR_UNNESTED_RESOURCE,
X509PermittedVolation = X509_V_ERR_PERMITTED_VIOLATION,
X509ExcludedViolation = X509_V_ERR_EXCLUDED_VIOLATION,
X509SubtreeMinmax = X509_V_ERR_SUBTREE_MINMAX,
X509UnsupportedConstraintType = X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE,
X509UnsupportedConstraintSyntax = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX,
X509UnsupportedNameSyntax = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX,
X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR,
X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION,
)
struct Ssl {
ssl: *ffi::SSL
}

30
test.rs
View File

@ -1,4 +1,4 @@
#[feature(struct_variant)];
#[feature(struct_variant, macro_rules)];
use std::io::Writer;
use std::io::net::tcp::TcpStream;
@ -115,6 +115,34 @@ fn test_verify_callback_load_certs() {
assert!(SslStream::try_new(&ctx, stream).is_ok());
}
#[test]
fn test_verify_trusted_get_error_ok() {
fn callback(_preverify_ok: bool, x509_ctx: X509StoreContext) -> bool {
assert!(x509_ctx.get_error().is_none());
true
}
let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap();
let mut ctx = SslContext::new(Sslv23);
ctx.set_verify(SslVerifyPeer, Some(callback));
match ctx.set_CA_file("test/cert.pem") {
None => {}
Some(err) => fail!("Unexpected error {:?}", err)
}
assert!(SslStream::try_new(&ctx, stream).is_ok());
}
#[test]
fn test_verify_trusted_get_error_err() {
fn callback(_preverify_ok: bool, x509_ctx: X509StoreContext) -> bool {
assert!(x509_ctx.get_error().is_some());
false
}
let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap();
let mut ctx = SslContext::new(Sslv23);
ctx.set_verify(SslVerifyPeer, Some(callback));
assert!(SslStream::try_new(&ctx, stream).is_err());
}
#[test]
fn test_write() {
let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap();