File Coverage

blib/lib/Config/Apple/Profile/Payload/Certificate.pm
Criterion Covered Total %
statement 58 60 96.6
branch 4 6 66.6
condition n/a
subroutine 14 15 93.3
pod 1 1 100.0
total 77 82 93.9


line stmt bran cond sub pod time code
1             # This is the code for Config::Apple::Profile::Payload::Certificate.
2             # For Copyright, please see the bottom of the file.
3              
4             package Config::Apple::Profile::Payload::Certificate;
5              
6 2     2   5619 use 5.10.1;
  2         6  
  2         86  
7 2     2   11 use strict;
  2         4  
  2         80  
8 2     2   11 use warnings FATAL => 'all';
  2         8  
  2         92  
9 2     2   10 use base qw(Config::Apple::Profile::Payload::Common);
  2         3  
  2         567  
10              
11             our $VERSION = '0.87';
12              
13 2     2   14 use Config::Apple::Profile::Config qw($ACP_OPENSSL_PATH);
  2         4  
  2         225  
14 2     2   10 use Config::Apple::Profile::Payload::Common;
  2         3  
  2         50  
15 2     2   8 use Config::Apple::Profile::Payload::Types qw(:all);
  2         6  
  2         384  
16 2     2   16 use Fcntl qw(:seek);
  2         3  
  2         205  
17 2     2   1073 use IPC::Open3;
  2         7551  
  2         103  
18 2     2   13 use Readonly;
  2         3  
  2         90  
19 2     2   11 use Symbol qw(gensym);
  2         4  
  2         78  
20 2     2   10 use Try::Tiny;
  2         4  
  2         785  
21              
22              
23             =encoding utf8
24              
25             =head1 NAME
26              
27             Config::Apple::Profile::Payload::Certificate - Base class for the four
28             different Certificate payload types.
29              
30             =head1 DESCRIPTION
31              
32             This class I implements the Certificate payload. This payload
33             is used to send certificates, and certificate-key pairs, to a device.
34              
35             This payload is typically used early in the provisioning process, in order to
36             load a non-standard certificate authority (or intermediate certificate) onto the
37             device. In addition, this payload can be used to load a user's private key and
38             public certificate onto the phone, so that it can be used for email (using
39             S/MIME) and web (client certificate) authentication.
40              
41             This payload may be used to hold root certificates or intermediate certificates.
42             The OS will examine the certificate when you try to install it, in order to
43             determine what type of certificate is being installed.
44              
45             B Installing a certificate does not automatically make it trusted! In
46             order for the OS to trust a certificate, the entire chain (from a root cert
47             down) must be present. Eveb if the root already exists on the device, you may
48             still need to install an intermediate certificate.
49              
50             B As per L, starting with iOS 5,
51             if a certificate chain includes a cert that uses MD5 hashing, then that cert,
52             I, will be untrusted. You should only ever use
53             certificates with SHA signatures, and preferably SHA-256 or better.
54              
55             B Typically, you will B use this module directly! Apple defines
56             four different types of certificate payloads, each with a different identifier.
57             Please use one of the L
58             subclasses.
59              
60              
61             =head1 INSTANCE METHODS
62              
63             The following instance methods are provided by this class.
64              
65             =head2 validate_cert($handle, $type)
66              
67             C<$handle> is an open, readable file handle. C<$type> is 'DER' or 'PEM'.
68              
69             If OpenSSL was found and validated during installation, then see if OpenSSL
70             can read the C<$type>-type certificate contained in C<$handle>.
71              
72             We rely on C<$ACP_OPENSSL_PATH> from L to tell
73             us if OpenSSL is installed.
74              
75             An exception will be thrown if a problem occurs trying to run OpenSSL. If
76             OpenSSL happens to exit with a non-zero exit code, that will be taken as a sign
77             that the certificate provided is invalid.
78              
79             =cut
80              
81             sub validate_cert {
82 6     6 1 12 my ($self, $handle, $type) = @_;
83            
84             # If OpenSSL is not installed, skip validation
85 6 50       16 return $handle
86             unless defined($ACP_OPENSSL_PATH);
87            
88 6 50       43 unless ($type =~ m/^(DER|PEM)$/m) {
89 0         0 die "Certificate type $type is invalid";
90             }
91 6         23 $type = $1;
92            
93             # Our OpenSSL command is:
94             # $ACP_OPENSSL_PATH x509 -inform $type -noout
95 6         7 my ($ssl_write, $ssl_read, $ssl_err, $ssl_pid);
96 6         19 $ssl_write = gensym;
97 6         100 $ssl_read = $ssl_err = gensym;
98             try {
99 6     6   185 $ssl_pid = open3($ssl_write, $ssl_read, $ssl_err,
100             $ACP_OPENSSL_PATH,
101             'x509', '-inform', $type, '-noout'
102             );
103             }
104             catch {
105 0     0   0 die "Error running $ACP_OPENSSL_PATH: $_";
106 6         171 };
107 6         17526 binmode($ssl_write);
108            
109             # Write our certificate to OpenSSL
110 6         19 my $cert_data;
111 6         27 seek $handle, 0, SEEK_SET;
112 6         88 while (read $handle, $cert_data, 1024) {
113 15         129 print $ssl_write $cert_data;
114             }
115 6         34 close $ssl_write;
116            
117             # We should not expect any output. A return code of zero is good!
118 6         22290 waitpid($ssl_pid, 0);
119 6         79 close $ssl_read;
120 6         27 my $ssl_exit = $? >> 8;
121 6 100       37 if ($ssl_exit == 0) {
122 3         10 seek $handle, 0, SEEK_SET;
123 3         66 return $handle;
124             }
125             else {
126             ## no critic (ProhibitExplicitReturnUndef)
127 3         82 return undef;
128             ## use critic
129             }
130             }
131              
132              
133             =head1 PAYLOAD KEYS
134              
135             All of the payload keys defined in L
136             are used by this payload.
137              
138             This payload has the following additional keys:
139              
140             =head2 C
141              
142             I
143              
144             The name of the certificate file. As far as the author knows, this isn't really
145             used for anything, but you never know!
146              
147             =head2 C
148              
149             This is where the actual certificate goes. The contents may be text (as in a
150             PEM-format certificate), or binary (as in a DER-format certificate).
151              
152             As a reminder, this key takes binary data, even if that data happens to be
153             text. You do not need to worry about the encoding.
154              
155             B iOS does not trust certificates that use MD5 as the signature
156             method. Such certificates can be installed, but they will not be trusted, and
157             will cause the user to see warnings.
158              
159             B Certificates with 1024-bit RSA keys are rapidly becoming untrusted
160             by browsers. Such certificates can be installed, but they are quickly going the
161             way of MD5 certificates (see the warning above).
162              
163             B Certificates with SHA-1 signatures are going to start losing trust
164             in many browsers starting in 2016. Plan ahead by minting new certificates with
165             SHA-256 signatures!
166              
167             =cut
168              
169             Readonly our %payloadKeys => (
170             # Bring in the common keys...
171             %Config::Apple::Profile::Payload::Common::payloadKeys,
172            
173             # ... and define our own!
174             'PayloadCertificateFileName' => {
175             type => $ProfileString,
176             description => "The certificate's filename.",
177             optional => 1,
178             },
179             'PayloadContent' => {
180             type => $ProfileData,
181             description => "The certificate's contents, in binary form.",
182             },
183             ); # End of %payloadKeys
184              
185              
186              
187             =head1 ACKNOWLEDGEMENTS
188              
189             Refer to L for acknowledgements.
190              
191             =head1 AUTHOR
192              
193             A. Karl Kornel, C<< >>
194              
195             =head1 COPYRIGHT AND LICENSE
196              
197             Copyright © 2014 A. Karl Kornel.
198              
199             This program is free software; you can redistribute it and/or modify it
200             under the terms of either: the GNU General Public License as published
201             by the Free Software Foundation; or the Artistic License.
202              
203             See L for more information.
204              
205             =cut
206              
207             1;