Commit 0b287710 authored by Steven Fackler's avatar Steven Fackler
Browse files

Certificate error codes

parent f8be6415
Loading
Loading
Loading
Loading
+65 −1
Original line number Diff line number Diff line
@@ -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);
+87 −1
Original line number Diff line number Diff line
#[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
}
+29 −1
Original line number Diff line number Diff line
#[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();