1#' X509 certificates
2#'
3#' Read, download, analyze and verify X.509 certificates.
4#'
5#' @useDynLib openssl R_cert_verify_cert R_pubkey_verify_cert
6#' @export
7#' @rdname certificates
8#' @seealso \link{read_cert}
9#' @param cert certificate (or certificate-chain) to be verified. Must be cert or list or path.
10#' @param root trusted pubkey or certificate(s) e.g. CA bundle.
11#' @examples # Verify the r-project HTTPS cert
12#' chain <- download_ssl_cert("cran.r-project.org", 443)
13#' print(chain)
14#' cert_data <- as.list(chain[[1]])
15#' print(cert_data$pubkey)
16#' print(cert_data$alt_names)
17#' cert_verify(chain, ca_bundle())
18#'
19#' # Write cert in PEM format
20#' cat(write_pem(chain[[1]]))
21cert_verify <- function(cert, root = ca_bundle()){
22  if(is.raw(cert))
23    cert <- list(cert)
24  if(!is.list(cert))
25    cert <- read_cert_bundle(cert)
26  stopifnot(inherits(cert[[1]], "cert"))
27  if(inherits(root, "cert"))
28    root <- list(root)
29  if(!is.raw(root) && !is.list(root)){
30    buf <- read_input(root)
31    names <- pem_names(buf)
32    if(any(grepl("CERT", names))){
33      root <- read_cert_bundle(root)
34    } else {
35      root <- read_pubkey(root)
36    }
37  }
38  if(inherits(root, "pubkey")){
39    pubkey_verify_cert(cert[[1]], root)
40  } else {
41    stopifnot(all(sapply(root, inherits, "cert")))
42    cert_verify_cert(cert[[1]], cert[-1], root)
43  }
44}
45
46#' @useDynLib openssl R_download_cert
47#' @export
48#' @rdname certificates
49#' @param host string: hostname of the server to connect to
50#' @param port string or integer: port or protocol to use, e.g: \code{443} or \code{"https"}
51#' @param ipv4_only do not use IPv6 connections
52download_ssl_cert <- function(host = "localhost", port = 443, ipv4_only = FALSE){
53  if(grepl("https?://", host))
54    stop("Argument 'host' must be a hostname, not url. Take out the https:// prefix.")
55  stopifnot(is.character(host))
56  .Call(R_download_cert, host, as.character(port), ipv4_only)
57}
58
59#' @useDynLib openssl R_cert_verify_cert
60cert_verify_cert <- function(cert, chain, root){
61  .Call(R_cert_verify_cert, cert, chain, root)
62}
63
64#' @useDynLib openssl R_pubkey_verify_cert
65pubkey_verify_cert <- function(cert, pubkey){
66  .Call(R_pubkey_verify_cert, cert, pubkey)
67}
68
69#' @export
70#' @rdname certificates
71ca_bundle <- function(){
72  path <- system.file("cacert.pem", package = "openssl")
73  read_cert_bundle(path)
74}
75
76#' @useDynLib openssl R_cert_info
77cert_info <- function(cert, name_format = NULL){
78  stopifnot(is.raw(cert))
79  if(length(name_format))
80    stopifnot(is.integer(name_format))
81  out <- .Call(R_cert_info, cert, name_format)
82  structure(out, names = c("subject", "issuer", "algorithm", "signature", "validity", "self_signed", "alt_names"))
83}
84