| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | =pod | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =encoding UTF-8 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 NAME | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | proxy-certificates - Proxy certificates in OpenSSL | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 DESCRIPTION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Proxy certificates are defined in RFC 3820.  They are used to | 
					
						
							|  |  |  | extend rights to some other entity (a computer process, typically, or | 
					
						
							|  |  |  | sometimes to the user itself).  This allows the entity to perform | 
					
						
							|  |  |  | operations on behalf of the owner of the EE (End Entity) certificate. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The requirements for a valid proxy certificate are: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =over 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | They are issued by an End Entity, either a normal EE certificate, or | 
					
						
							|  |  |  | another proxy certificate. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | They must not have the B<subjectAltName> or B<issuerAltName> | 
					
						
							|  |  |  | extensions. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | They must have the B<proxyCertInfo> extension. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | They must have the subject of their issuer, with one B<commonName> | 
					
						
							|  |  |  | added. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =back | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head2 Enabling proxy certificate verification | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | OpenSSL expects applications that want to use proxy certificates to be | 
					
						
							|  |  |  | specially aware of them, and make that explicit.  This is done by | 
					
						
							|  |  |  | setting an X509 verification flag: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | or | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_ALLOW_PROXY_CERTS); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See L</NOTES> for a discussion on this requirement. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head2 Creating proxy certificates | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Creating proxy certificates can be done using the L<openssl-x509(1)> | 
					
						
							|  |  |  | command, with some extra extensions: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     [ proxy ] | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  |     # A proxy certificate MUST NEVER be a CA certificate. | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     basicConstraints = CA:FALSE | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  |     # Usual authority key ID | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     authorityKeyIdentifier = keyid,issuer:always | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  |     # The extension which marks this certificate as a proxy | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     proxyCertInfo = critical,language:id-ppl-anyLanguage,pathlen:1,policy:text:AB | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | It's also possible to specify the proxy extension in a separate section: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     proxyCertInfo = critical,@proxy_ext | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     [ proxy_ext ] | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |     language = id-ppl-anyLanguage | 
					
						
							|  |  |  |     pathlen = 0 | 
					
						
							|  |  |  |     policy = text:BC | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | The policy value has a specific syntax, I<syntag>:I<string>, where the | 
					
						
							|  |  |  | I<syntag> determines what will be done with the string.  The following | 
					
						
							|  |  |  | I<syntag>s are recognised: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =over 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item B<text> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | indicates that the string is a byte sequence, without any encoding: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     policy=text:räksmörgås | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item B<hex> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | indicates the string is encoded hexadecimal encoded binary data, with | 
					
						
							|  |  |  | colons between each byte (every second hex digit): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     policy=hex:72:E4:6B:73:6D:F6:72:67:E5:73 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item B<file> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | indicates that the text of the policy should be taken from a file. | 
					
						
							|  |  |  | The string is then a filename.  This is useful for policies that are | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  | more than a few lines, such as XML or other markup. | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | =back | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  | Note that the proxy policy value is what determines the rights granted | 
					
						
							|  |  |  | to the process during the proxy certificate, and it is up to the | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | application to interpret and combine these policies.> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | With a proxy extension, creating a proxy certificate is a matter of | 
					
						
							|  |  |  | two commands: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     openssl req -new -config proxy.cnf \ | 
					
						
							|  |  |  |         -out proxy.req -keyout proxy.key \ | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |         -subj "/DC=org/DC=openssl/DC=users/CN=proxy" | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     openssl x509 -req -CAcreateserial -in proxy.req -out proxy.crt \ | 
					
						
							|  |  |  |         -CA user.crt -CAkey user.key -days 7 \ | 
					
						
							| 
									
										
										
										
											2020-03-05 03:08:31 +08:00
										 |  |  |         -extfile proxy.cnf -extensions proxy | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | You can also create a proxy certificate using another proxy | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  | certificate as issuer. Note that this example uses a different | 
					
						
							|  |  |  | configuration section for the proxy extensions: | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     openssl req -new -config proxy.cnf \ | 
					
						
							|  |  |  |         -out proxy2.req -keyout proxy2.key \ | 
					
						
							| 
									
										
										
										
											2020-04-28 00:57:01 +08:00
										 |  |  |         -subj "/DC=org/DC=openssl/DC=users/CN=proxy/CN=proxy 2" | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     openssl x509 -req -CAcreateserial -in proxy2.req -out proxy2.crt \ | 
					
						
							|  |  |  |         -CA proxy.crt -CAkey proxy.key -days 7 \ | 
					
						
							| 
									
										
										
										
											2020-03-05 03:08:31 +08:00
										 |  |  |         -extfile proxy.cnf -extensions proxy_2 | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | =head2 Using proxy certs in applications | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To interpret proxy policies, the application would normally start with | 
					
						
							|  |  |  | some default rights (perhaps none at all), then compute the resulting | 
					
						
							|  |  |  | rights by checking the rights against the chain of proxy certificates, | 
					
						
							|  |  |  | user certificate and CA certificates. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The complicated part is figuring out how to pass data between your | 
					
						
							|  |  |  | application and the certificate validation procedure. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following ingredients are needed for such processing: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =over 4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | a callback function that will be called for every certificate being | 
					
						
							|  |  |  | validated.  The callback is called several times for each certificate, | 
					
						
							|  |  |  | so you must be careful to do the proxy policy interpretation at the | 
					
						
							|  |  |  | right time.  You also need to fill in the defaults when the EE | 
					
						
							|  |  |  | certificate is checked. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | a data structure that is shared between your application code and the | 
					
						
							|  |  |  | callback. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | a wrapper function that sets it all up. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =item * | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | an ex_data index function that creates an index into the generic | 
					
						
							|  |  |  | ex_data store that is attached to an X509 validation context. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =back | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The following skeleton code can be used as a starting point: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #include <string.h> | 
					
						
							|  |  |  |     #include <netdb.h> | 
					
						
							|  |  |  |     #include <openssl/x509.h> | 
					
						
							|  |  |  |     #include <openssl/x509v3.h> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #define total_rights 25 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* | 
					
						
							|  |  |  |      * In this example, I will use a view of granted rights as a bit | 
					
						
							|  |  |  |      * array, one bit for each possible right. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     typedef struct your_rights { | 
					
						
							|  |  |  |         unsigned char rights[(total_rights + 7) / 8]; | 
					
						
							|  |  |  |     } YOUR_RIGHTS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* | 
					
						
							|  |  |  |      * The following procedure will create an index for the ex_data | 
					
						
							|  |  |  |      * store in the X509 validation context the first time it's | 
					
						
							|  |  |  |      * called.  Subsequent calls will return the same index. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static int get_proxy_auth_ex_data_idx(X509_STORE_CTX *ctx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         static volatile int idx = -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (idx < 0) { | 
					
						
							|  |  |  |             X509_STORE_lock(X509_STORE_CTX_get0_store(ctx)); | 
					
						
							|  |  |  |             if (idx < 0) { | 
					
						
							|  |  |  |                 idx = X509_STORE_CTX_get_ex_new_index(0, | 
					
						
							|  |  |  |                                                       "for verify callback", | 
					
						
							|  |  |  |                                                       NULL,NULL,NULL); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             X509_STORE_unlock(X509_STORE_CTX_get0_store(ctx)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return idx; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Callback to be given to the X509 validation procedure.  */ | 
					
						
							|  |  |  |     static int verify_callback(int ok, X509_STORE_CTX *ctx) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (ok == 1) { | 
					
						
							|  |  |  |             /* | 
					
						
							|  |  |  |              * It's REALLY important you keep the proxy policy check | 
					
						
							|  |  |  |              * within this section.  It's important to know that when | 
					
						
							|  |  |  |              * ok is 1, the certificates are checked from top to | 
					
						
							|  |  |  |              * bottom.  You get the CA root first, followed by the | 
					
						
							|  |  |  |              * possible chain of intermediate CAs, followed by the EE | 
					
						
							|  |  |  |              * certificate, followed by the possible proxy | 
					
						
							|  |  |  |              * certificates.  | 
					
						
							|  |  |  |              */ | 
					
						
							|  |  |  |             X509 *xs = X509_STORE_CTX_get_current_cert(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (X509_get_extension_flags(xs) & EXFLAG_PROXY) { | 
					
						
							|  |  |  |                 YOUR_RIGHTS *rights = | 
					
						
							|  |  |  |                     (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, | 
					
						
							|  |  |  |                         get_proxy_auth_ex_data_idx(ctx)); | 
					
						
							|  |  |  |                 PROXY_CERT_INFO_EXTENSION *pci = | 
					
						
							|  |  |  |                     X509_get_ext_d2i(xs, NID_proxyCertInfo, NULL, NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 switch (OBJ_obj2nid(pci->proxyPolicy->policyLanguage)) { | 
					
						
							|  |  |  |                 case NID_Independent: | 
					
						
							|  |  |  |                     /* | 
					
						
							|  |  |  |                      * Do whatever you need to grant explicit rights | 
					
						
							|  |  |  |                      * to this particular proxy certificate, usually | 
					
						
							|  |  |  |                      * by pulling them from some database.  If there | 
					
						
							|  |  |  |                      * are none to be found, clear all rights (making | 
					
						
							|  |  |  |                      * this and any subsequent proxy certificate void | 
					
						
							|  |  |  |                      * of any rights).  | 
					
						
							|  |  |  |                      */ | 
					
						
							|  |  |  |                     memset(rights->rights, 0, sizeof(rights->rights)); | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 case NID_id_ppl_inheritAll: | 
					
						
							|  |  |  |                     /* | 
					
						
							|  |  |  |                      * This is basically a NOP, we simply let the | 
					
						
							|  |  |  |                      * current rights stand as they are. | 
					
						
							|  |  |  |                      */ | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 default: | 
					
						
							|  |  |  |                     /* | 
					
						
							|  |  |  |                      * This is usually the most complex section of | 
					
						
							|  |  |  |                      * code.  You really do whatever you want as long | 
					
						
							|  |  |  |                      * as you follow RFC 3820.  In the example we use | 
					
						
							|  |  |  |                      * here, the simplest thing to do is to build | 
					
						
							|  |  |  |                      * another, temporary bit array and fill it with | 
					
						
							|  |  |  |                      * the rights granted by the current proxy | 
					
						
							|  |  |  |                      * certificate, then use it as a mask on the | 
					
						
							|  |  |  |                      * accumulated rights bit array, and voilà, you | 
					
						
							|  |  |  |                      * now have a new accumulated rights bit array. | 
					
						
							|  |  |  |                      */ | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         int i; | 
					
						
							|  |  |  |                         YOUR_RIGHTS tmp_rights; | 
					
						
							|  |  |  |                         memset(tmp_rights.rights, 0, | 
					
						
							|  |  |  |                                sizeof(tmp_rights.rights)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         /* | 
					
						
							|  |  |  |                          * process_rights() is supposed to be a | 
					
						
							|  |  |  |                          * procedure that takes a string and its | 
					
						
							|  |  |  |                          * length, interprets it and sets the bits | 
					
						
							|  |  |  |                          * in the YOUR_RIGHTS pointed at by the | 
					
						
							|  |  |  |                          * third argument. | 
					
						
							|  |  |  |                          */ | 
					
						
							|  |  |  |                         process_rights((char *) pci->proxyPolicy->policy->data, | 
					
						
							|  |  |  |                                        pci->proxyPolicy->policy->length, | 
					
						
							|  |  |  |                                        &tmp_rights); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         for(i = 0; i < total_rights / 8; i++) | 
					
						
							|  |  |  |                             rights->rights[i] &= tmp_rights.rights[i]; | 
					
						
							|  |  |  |                     } | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 PROXY_CERT_INFO_EXTENSION_free(pci); | 
					
						
							|  |  |  |             } else if (!(X509_get_extension_flags(xs) & EXFLAG_CA)) { | 
					
						
							|  |  |  |                 /* We have an EE certificate, let's use it to set default! */ | 
					
						
							|  |  |  |                 YOUR_RIGHTS *rights = | 
					
						
							|  |  |  |                     (YOUR_RIGHTS *)X509_STORE_CTX_get_ex_data(ctx, | 
					
						
							|  |  |  |                         get_proxy_auth_ex_data_idx(ctx)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 /* | 
					
						
							|  |  |  |                  * The following procedure finds out what rights the | 
					
						
							|  |  |  |                  * owner of the current certificate has, and sets them | 
					
						
							|  |  |  |                  * in the YOUR_RIGHTS structure pointed at by the | 
					
						
							|  |  |  |                  * second argument. | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |                 set_default_rights(xs, rights); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return ok; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static int my_X509_verify_cert(X509_STORE_CTX *ctx, | 
					
						
							|  |  |  |                                    YOUR_RIGHTS *needed_rights) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         int ok; | 
					
						
							|  |  |  |         int (*save_verify_cb)(int ok,X509_STORE_CTX *ctx) = | 
					
						
							|  |  |  |             X509_STORE_CTX_get_verify_cb(ctx); | 
					
						
							|  |  |  |         YOUR_RIGHTS rights; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         X509_STORE_CTX_set_verify_cb(ctx, verify_callback); | 
					
						
							|  |  |  |         X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(ctx), | 
					
						
							|  |  |  |                                    &rights); | 
					
						
							|  |  |  |         X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS); | 
					
						
							|  |  |  |         ok = X509_verify_cert(ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (ok == 1) { | 
					
						
							|  |  |  |             ok = check_needed_rights(rights, needed_rights); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         X509_STORE_CTX_set_verify_cb(ctx, save_verify_cb); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return ok; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you use SSL or TLS, you can easily set up a callback to have the | 
					
						
							|  |  |  | certificates checked properly, using the code above: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     SSL_CTX_set_cert_verify_callback(s_ctx, my_X509_verify_cert, | 
					
						
							|  |  |  |                                      &needed_rights); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 NOTES | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To this date, it seems that proxy certificates have only been used in | 
					
						
							|  |  |  | environments that are aware of them, and no one seems to have | 
					
						
							|  |  |  | investigated how they can be used or misused outside of such an | 
					
						
							|  |  |  | environment. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For that reason, OpenSSL requires that applications aware of proxy | 
					
						
							|  |  |  | certificates must also make that explicit. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | B<subjectAltName> and B<issuerAltName> are forbidden in proxy | 
					
						
							|  |  |  | certificates, and this is enforced in OpenSSL.  The subject must be | 
					
						
							|  |  |  | the same as the issuer, with one commonName added on. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 SEE ALSO | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | L<X509_STORE_CTX_set_flags(3)>, | 
					
						
							|  |  |  | L<X509_STORE_CTX_set_verify_cb(3)>, | 
					
						
							|  |  |  | L<X509_VERIFY_PARAM_set_flags(3)>, | 
					
						
							|  |  |  | L<SSL_CTX_set_cert_verify_callback(3)>, | 
					
						
							|  |  |  | L<openssl-req(1)>, L<openssl-x509(1)>, | 
					
						
							|  |  |  | L<RFC 3820|https://tools.ietf.org/html/rfc3820> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =head1 COPYRIGHT | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:33:57 +08:00
										 |  |  | Copyright 2019-2020 The OpenSSL Project Authors. All Rights Reserved. | 
					
						
							| 
									
										
										
										
											2019-11-23 17:36:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | Licensed under the Apache License 2.0 (the "License").  You may not use | 
					
						
							|  |  |  | this file except in compliance with the License.  You can obtain a copy | 
					
						
							|  |  |  | in the file LICENSE in the source distribution or at | 
					
						
							|  |  |  | L<https://www.openssl.org/source/license.html>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | =cut |