| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | 
| 2 |  |  |  |  |  |  | package Net::SSLeay::OO::Error; | 
| 3 |  |  |  |  |  |  |  | 
| 4 | 3 |  |  | 3 |  | 17 | use Net::SSLeay; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 165 |  | 
| 5 | 3 |  |  | 3 |  | 240012 | use Moose; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  |  | 
| 7 |  |  |  |  |  |  | has 'err'        => isa => 'Int', | 
| 8 |  |  |  |  |  |  | is       => 'ro', | 
| 9 |  |  |  |  |  |  | required => 1, | 
| 10 |  |  |  |  |  |  | default  => sub { | 
| 11 |  |  |  |  |  |  | Net::SSLeay::ERR_get_error | 
| 12 |  |  |  |  |  |  | or die "no OpenSSL error to get"; | 
| 13 |  |  |  |  |  |  | }; | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | sub ssl_error_pending { | 
| 16 |  |  |  |  |  |  | Net::SSLeay::ERR_peek_error; | 
| 17 |  |  |  |  |  |  | } | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | has 'error_code' => isa => "Int", | 
| 20 |  |  |  |  |  |  | is       => "ro", | 
| 21 |  |  |  |  |  |  | ; | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | has 'library_name' => isa => "Str", | 
| 24 |  |  |  |  |  |  | is         => "ro", | 
| 25 |  |  |  |  |  |  | ; | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | has 'function_name' => isa => "Str", | 
| 28 |  |  |  |  |  |  | is          => "ro", | 
| 29 |  |  |  |  |  |  | ; | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | has 'reason_string' => isa => "Str", | 
| 32 |  |  |  |  |  |  | is          => "ro", | 
| 33 |  |  |  |  |  |  | ; | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | has 'next' => isa => __PACKAGE__, | 
| 36 |  |  |  |  |  |  | is => "ro", | 
| 37 |  |  |  |  |  |  | ; | 
| 38 |  |  |  |  |  |  |  | 
| 39 |  |  |  |  |  |  | sub BUILD { | 
| 40 |  |  |  |  |  |  | my $self      = shift; | 
| 41 |  |  |  |  |  |  | my $ssl_error = $self->error_string; | 
| 42 |  |  |  |  |  |  | ( undef, my @fields ) = split ":", $ssl_error, 5; | 
| 43 |  |  |  |  |  |  | $self->{error_code}    ||= hex( shift @fields ); | 
| 44 |  |  |  |  |  |  | $self->{library_name}  ||= shift @fields; | 
| 45 |  |  |  |  |  |  | $self->{function_name} ||= shift @fields; | 
| 46 |  |  |  |  |  |  | $self->{reason_string} ||= shift @fields; | 
| 47 |  |  |  |  |  |  |  | 
| 48 |  |  |  |  |  |  | # OpenSSL throws an entire stack backtrace, so capture all the | 
| 49 |  |  |  |  |  |  | # outstanding SSL errors and chain them off this one. | 
| 50 |  |  |  |  |  |  | if (ssl_error_pending) { | 
| 51 |  |  |  |  |  |  | $self->{next} = ( ref $self )->new(); | 
| 52 |  |  |  |  |  |  | } | 
| 53 |  |  |  |  |  |  | } | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | has 'message' => isa => "Str", | 
| 56 |  |  |  |  |  |  | is    => "rw", | 
| 57 |  |  |  |  |  |  | ; | 
| 58 |  |  |  |  |  |  |  | 
| 59 |  |  |  |  |  |  | sub die_if_ssl_error { | 
| 60 |  |  |  |  |  |  | my $message = shift; | 
| 61 |  |  |  |  |  |  | if (ssl_error_pending) { | 
| 62 |  |  |  |  |  |  | die __PACKAGE__->new( message => $message ); | 
| 63 |  |  |  |  |  |  | } | 
| 64 |  |  |  |  |  |  | } | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | sub as_string { | 
| 67 |  |  |  |  |  |  | my $self    = shift; | 
| 68 |  |  |  |  |  |  | my $message = $self->message; | 
| 69 |  |  |  |  |  |  | if ($message) { | 
| 70 |  |  |  |  |  |  | unless ( $message =~ / / ) { | 
| 71 |  |  |  |  |  |  | $message = "During `$message'"; | 
| 72 |  |  |  |  |  |  | } | 
| 73 |  |  |  |  |  |  | $message .= ": "; | 
| 74 |  |  |  |  |  |  | } | 
| 75 |  |  |  |  |  |  | else { | 
| 76 |  |  |  |  |  |  | $message = ""; | 
| 77 |  |  |  |  |  |  | } | 
| 78 |  |  |  |  |  |  | my $reason_string = $self->reason_string; | 
| 79 |  |  |  |  |  |  | my $result        = do { | 
| 80 |  |  |  |  |  |  | if ( $reason_string eq "system lib" ) {    # FIXME: lang | 
| 81 |  |  |  |  |  |  | sprintf( "%s%.8x: trace: %s (%s)", | 
| 82 |  |  |  |  |  |  | $message, $self->error_code, | 
| 83 |  |  |  |  |  |  | $self->function_name, $self->library_name ); | 
| 84 |  |  |  |  |  |  | } | 
| 85 |  |  |  |  |  |  | else { | 
| 86 |  |  |  |  |  |  | sprintf("%sOpenSSL error %.8x: %s during %s (%s)", | 
| 87 |  |  |  |  |  |  | $message,             $self->error_code, | 
| 88 |  |  |  |  |  |  | $self->reason_string, $self->function_name, | 
| 89 |  |  |  |  |  |  | $self->library_name | 
| 90 |  |  |  |  |  |  | ); | 
| 91 |  |  |  |  |  |  | } | 
| 92 |  |  |  |  |  |  | }; | 
| 93 |  |  |  |  |  |  | if ( $self->next ) { | 
| 94 |  |  |  |  |  |  | $result .= "\n" . "    then " . $self->next->as_string; | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  | if ( $result =~ m{\n} and $result !~ m{\n\Z} ) { | 
| 97 |  |  |  |  |  |  | $result .= "\n"; | 
| 98 |  |  |  |  |  |  | } | 
| 99 |  |  |  |  |  |  | $result; | 
| 100 |  |  |  |  |  |  | } | 
| 101 |  |  |  |  |  |  |  | 
| 102 |  |  |  |  |  |  | use overload | 
| 103 |  |  |  |  |  |  | '""' => \&as_string, | 
| 104 |  |  |  |  |  |  | ; | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | use Sub::Exporter -setup => | 
| 107 |  |  |  |  |  |  | { exports => [qw(die_if_ssl_error ssl_error_pending)], }; | 
| 108 |  |  |  |  |  |  |  | 
| 109 |  |  |  |  |  |  | use Net::SSLeay::OO::Functions sub { | 
| 110 |  |  |  |  |  |  | my $code = shift; | 
| 111 |  |  |  |  |  |  | sub { | 
| 112 |  |  |  |  |  |  | my $self = shift; | 
| 113 |  |  |  |  |  |  | $code->( $self->err, @_ ); | 
| 114 |  |  |  |  |  |  | } | 
| 115 |  |  |  |  |  |  | }; | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | 1; | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | __END__ | 
| 120 |  |  |  |  |  |  |  | 
| 121 |  |  |  |  |  |  | =head1 NAME | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | Net::SSLeay::OO::Error - encapsulated SSLeay errors | 
| 124 |  |  |  |  |  |  |  | 
| 125 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | use Scalar::Util qw(blessed); | 
| 128 |  |  |  |  |  |  | eval { | 
| 129 |  |  |  |  |  |  | $ctx->use_PrivateKey_file($filename, FILETYPE_PEM); | 
| 130 |  |  |  |  |  |  | }; | 
| 131 |  |  |  |  |  |  | my $error = $@; | 
| 132 |  |  |  |  |  |  | if (blessed $error and | 
| 133 |  |  |  |  |  |  | ( $error->error_code == 0x0B080074 or | 
| 134 |  |  |  |  |  |  | $error->reason_string =~ /key.*mismatch/i ) ) { | 
| 135 |  |  |  |  |  |  | # deal with some known error condition differently.. | 
| 136 |  |  |  |  |  |  | die "Private key file mismatches certificate file, did " | 
| 137 |  |  |  |  |  |  | ."you update both settings?"; | 
| 138 |  |  |  |  |  |  | } | 
| 139 |  |  |  |  |  |  | elsif ($error) { | 
| 140 |  |  |  |  |  |  | die $error; | 
| 141 |  |  |  |  |  |  | } | 
| 142 |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  | # if you need to manually check for errors ever | 
| 144 |  |  |  |  |  |  | use Net::SSLeay::OO::Error qw(die_if_ssl_error ssl_error_pending); | 
| 145 |  |  |  |  |  |  | die_if_ssl_error("Initialization"); | 
| 146 |  |  |  |  |  |  |  | 
| 147 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | Unlike L<Net::SSLeay>, with L<Net::SSLeay::OO> functions, if an error | 
| 150 |  |  |  |  |  |  | occurs in a low level library an exception is raised via C<die>. | 
| 151 |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  | OpenSSL has an 'error queue', which normally represents something like | 
| 153 |  |  |  |  |  |  | a stack trace indicating the context of the error.  The first error | 
| 154 |  |  |  |  |  |  | will be the "deepest" error and usually has the most relevant error | 
| 155 |  |  |  |  |  |  | message.  To represent this, the Net::SSLeay::OO::Error object has a | 
| 156 |  |  |  |  |  |  | B<next> property, which represents a level further up the exception | 
| 157 |  |  |  |  |  |  | heirarchy. | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | =head1 METHODS | 
| 160 |  |  |  |  |  |  |  | 
| 161 |  |  |  |  |  |  | The following methods are defined (some via L<Moose> attributes): | 
| 162 |  |  |  |  |  |  |  | 
| 163 |  |  |  |  |  |  | =over | 
| 164 |  |  |  |  |  |  |  | 
| 165 |  |  |  |  |  |  | =item B<error_string()> | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | Returns the error string from OpenSSL. | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | =item B<as_string()> | 
| 170 |  |  |  |  |  |  |  | 
| 171 |  |  |  |  |  |  | Returns the error string, turned into a marginally more user-friendly | 
| 172 |  |  |  |  |  |  | message.  Also available as the overloaded '""' operator (ie, when | 
| 173 |  |  |  |  |  |  | interpreted as a string you will get a message) | 
| 174 |  |  |  |  |  |  |  | 
| 175 |  |  |  |  |  |  | =item B<error_code()> | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | A fixed error code corresponding to the error. | 
| 178 |  |  |  |  |  |  |  | 
| 179 |  |  |  |  |  |  | =item B<reason_string()> | 
| 180 |  |  |  |  |  |  |  | 
| 181 |  |  |  |  |  |  | The human-readable part, or (apparently) "system lib" if the error is | 
| 182 |  |  |  |  |  |  | part of a stack trace. | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | =item B<library_name()> | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | =item B<function_name()> | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | Where the error occurred, or where this part of the stack trace | 
| 189 |  |  |  |  |  |  | applies. | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | =item B<next()> | 
| 192 |  |  |  |  |  |  |  | 
| 193 |  |  |  |  |  |  | The next (shallower) Net::SSLeay::OO::Error object, corresponding to the | 
| 194 |  |  |  |  |  |  | next level up the stack trace. | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | =item B<message( [$message] )> | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | The caller-supplied message that this error will be prefixed with.  If | 
| 199 |  |  |  |  |  |  | this is a single word (no whitespace) then it will be printed as | 
| 200 |  |  |  |  |  |  | C<During `$message':>. | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | =back | 
| 203 |  |  |  |  |  |  |  | 
| 204 |  |  |  |  |  |  | =head1 FUNCTIONS | 
| 205 |  |  |  |  |  |  |  | 
| 206 |  |  |  |  |  |  | These functions are available for export. | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | =over | 
| 209 |  |  |  |  |  |  |  | 
| 210 |  |  |  |  |  |  | =item B<die_if_ssl_error($message)> | 
| 211 |  |  |  |  |  |  |  | 
| 212 |  |  |  |  |  |  | This is similar to L<Net::SSLeay>'s function of the same name, except; | 
| 213 |  |  |  |  |  |  |  | 
| 214 |  |  |  |  |  |  | =over | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | =item 1. | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | The entire error queue is cleared, and wrapped into a single | 
| 219 |  |  |  |  |  |  | chain of exception objects | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | =item 2. | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | The message is parceled to be hopefully a little more human-readable. | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | =back | 
| 226 |  |  |  |  |  |  |  | 
| 227 |  |  |  |  |  |  | Here is an example, an error raised during the test suite script | 
| 228 |  |  |  |  |  |  | F<t/03-ssl.t>: | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | During `use_certificate_file': OpenSSL error 02001002: No such file or directory during fopen (system library) | 
| 231 |  |  |  |  |  |  | then 20074002: trace: FILE_CTRL (BIO routines) | 
| 232 |  |  |  |  |  |  | then 140c8002: trace: SSL_use_certificate_file (SSL routines) | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | The function was called as: | 
| 235 |  |  |  |  |  |  | C<die_if_ssl_error("use_certificate_file")> | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  | The strings returned from OpenSSL as a "human readable" error messages | 
| 238 |  |  |  |  |  |  | were: | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | error:02001002:system library:fopen:No such file or directory | 
| 241 |  |  |  |  |  |  | error:20074002:BIO routines:FILE_CTRL:system lib | 
| 242 |  |  |  |  |  |  | error:140C8002:SSL routines:SSL_use_certificate_file:system lib | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | =item B<ssl_error_pending()> | 
| 245 |  |  |  |  |  |  |  | 
| 246 |  |  |  |  |  |  | Returns a non-zero integer if there is an error pending.  To fetch it, | 
| 247 |  |  |  |  |  |  | just create a new L<Net::SSLeay::OO::Error> object. | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | =back | 
| 250 |  |  |  |  |  |  |  | 
| 251 |  |  |  |  |  |  | =head1 AUTHOR | 
| 252 |  |  |  |  |  |  |  | 
| 253 |  |  |  |  |  |  | Sam Vilain, L<samv@cpan.org> | 
| 254 |  |  |  |  |  |  |  | 
| 255 |  |  |  |  |  |  | =head1 COPYRIGHT | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | Copyright (C) 2009  NZ Registry Services | 
| 258 |  |  |  |  |  |  |  | 
| 259 |  |  |  |  |  |  | This program is free software: you can redistribute it and/or modify | 
| 260 |  |  |  |  |  |  | it under the terms of the Artistic License 2.0 or later.  You should | 
| 261 |  |  |  |  |  |  | have received a copy of the Artistic License the file COPYING.txt.  If | 
| 262 |  |  |  |  |  |  | not, see <http://www.perlfoundation.org/artistic_license_2_0> | 
| 263 |  |  |  |  |  |  |  | 
| 264 |  |  |  |  |  |  | =head1 SEE ALSO | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | L<Net::SSLeay::OO> | 
| 267 |  |  |  |  |  |  |  | 
| 268 |  |  |  |  |  |  | =cut | 
| 269 |  |  |  |  |  |  |  | 
| 270 |  |  |  |  |  |  | # Local Variables: | 
| 271 |  |  |  |  |  |  | # mode:cperl | 
| 272 |  |  |  |  |  |  | # indent-tabs-mode: t | 
| 273 |  |  |  |  |  |  | # cperl-continued-statement-offset: 8 | 
| 274 |  |  |  |  |  |  | # cperl-brace-offset: 0 | 
| 275 |  |  |  |  |  |  | # cperl-close-paren-offset: 0 | 
| 276 |  |  |  |  |  |  | # cperl-continued-brace-offset: 0 | 
| 277 |  |  |  |  |  |  | # cperl-continued-statement-offset: 8 | 
| 278 |  |  |  |  |  |  | # cperl-extra-newline-before-brace: nil | 
| 279 |  |  |  |  |  |  | # cperl-indent-level: 8 | 
| 280 |  |  |  |  |  |  | # cperl-indent-parens-as-block: t | 
| 281 |  |  |  |  |  |  | # cperl-indent-wrt-brace: nil | 
| 282 |  |  |  |  |  |  | # cperl-label-offset: -8 | 
| 283 |  |  |  |  |  |  | # cperl-merge-trailing-else: t | 
| 284 |  |  |  |  |  |  | # End: | 
| 285 |  |  |  |  |  |  | # vim: filetype=perl:noexpandtab:ts=3:sw=3 |