+/* Reads the X509 certificate or certificates in file 'file_name'. On success,
+ * stores the address of the first element in an array of pointers to
+ * certificates in '*certs' and the number of certificates in the array in
+ * '*n_certs', and returns 0. On failure, stores a null pointer in '*certs', 0
+ * in '*n_certs', and returns a positive errno value.
+ *
+ * The caller is responsible for freeing '*certs'. */
+int
+read_cert_file(const char *file_name, X509 ***certs, size_t *n_certs)
+{
+ FILE *file;
+ size_t allocated_certs = 0;
+
+ *certs = NULL;
+ *n_certs = 0;
+
+ file = fopen(file_name, "r");
+ if (!file) {
+ VLOG_ERR("failed to open %s for reading: %s",
+ file_name, strerror(errno));
+ return errno;
+ }
+
+ for (;;) {
+ X509 *certificate;
+ int c;
+
+ /* Read certificate from file. */
+ certificate = PEM_read_X509(file, NULL, NULL, NULL);
+ if (!certificate) {
+ size_t i;
+
+ VLOG_ERR("PEM_read_X509 failed reading %s: %s",
+ file_name, ERR_error_string(ERR_get_error(), NULL));
+ for (i = 0; i < *n_certs; i++) {
+ X509_free((*certs)[i]);
+ }
+ free(*certs);
+ *certs = NULL;
+ *n_certs = 0;
+ return EIO;
+ }
+
+ /* Add certificate to array. */
+ if (*n_certs >= allocated_certs) {
+ allocated_certs = 1 + 2 * allocated_certs;
+ *certs = xrealloc(*certs, sizeof *certs * allocated_certs);
+ }
+ (*certs)[(*n_certs)++] = certificate;
+
+ /* Are there additional certificates in the file? */
+ do {
+ c = getc(file);
+ } while (isspace(c));
+ if (c == EOF) {
+ break;
+ }
+ ungetc(c, file);
+ }
+ fclose(file);
+ return 0;
+}
+
+
+/* Sets 'file_name' as the name of a file containing one or more X509
+ * certificates to send to the peer. Typical use in OpenFlow is to send the CA
+ * certificate to the peer, which enables a switch to pick up the controller's
+ * CA certificate on its first connection. */