HTTPS/Client-authenticated: Difference between revisions

From Rosetta Code
Content added Content deleted
({{omit from|ZX Spectrum Basic|Does not have network access.}})
m (→‎{{header|Wren}}: Another minor change)
 
(47 intermediate revisions by 32 users not shown)
Line 4: Line 4:


This task is in general useful for use with [[Creating a SOAP Client|webservice client]]s as it offers a high level of assurance that the client is an acceptable counterparty for the server. For example, [http://aws.amazon.com/ Amazon Web Services] uses this style of authentication.
This task is in general useful for use with [[Creating a SOAP Client|webservice client]]s as it offers a high level of assurance that the client is an acceptable counterparty for the server. For example, [http://aws.amazon.com/ Amazon Web Services] uses this style of authentication.

=={{header|Arturo}}==

<syntaxhighlight lang="arturo">r: request.get.certificate:"mycert.pem" "https://www.example.com" ø</syntaxhighlight>

=={{header|C sharp|C#}}==
{{works with|C sharp|3.0}}

<syntaxhighlight lang="csharp">
using System;
using System.Net;

class Program
{
class MyWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
request.ClientCertificates.Add(new X509Certificate());
return request;
}
}
static void Main(string[] args)
{
var client = new MyWebClient();

var data = client.DownloadString("https://example.com");

Console.WriteLine(data);
}
}
</syntaxhighlight>

=={{header|Go}}==
<syntaxhighlight lang="go">package main

import (
"crypto/tls"
"io/ioutil"
"log"
"net/http"
)

func main() {

// load key pair
cert, err := tls.LoadX509KeyPair(
"./client.local.tld/client.local.tld.crt",
"./client.local.tld/client.local.tld.key",
)

if err != nil {
log.Fatal("Error while loading x509 key pair", err)
}

// Create TLS Config in order to had client certificate
tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}

tlsConfig.BuildNameToCertificate()
transport := &http.Transport{TLSClientConfig: tlsConfig}

// create http client with our custom transport with TLS config
client := &http.Client{Transport: transport}

res, err := client.Get("https://www.example.com/")
if err != nil {
log.Fatal(err)
}
contents, err := ioutil.ReadAll(res.Body)
log.Print(string(contents))

}
</syntaxhighlight>

=={{header|Java}}==
<syntaxhighlight lang="java">

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.net.URI;
import java.net.URL;
import java.security.KeyStore;
import java.util.Scanner;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

public final class HTTPSClientAuthenticated {

public static void main(String[] aArgs) throws Exception {
final String keyStorePath = "the/path/to/keystore"; // The key store contains the client's certificate
final String keyStorePassword = "my-password";
SSLContext sslContext = getSSLContext(keyStorePath, keyStorePassword);
URL url = new URI("https://somehost.com").toURL();
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
// Obtain response from the url
BufferedInputStream response = (BufferedInputStream) connection.getInputStream();
try ( Scanner scanner = new Scanner(response) ) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
}
private static SSLContext getSSLContext(String aPath, String aPassword) throws Exception {
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load( new FileInputStream(aPath), aPassword.toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
keyManagerFactory.init(keyStore, aPassword.toCharArray());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
return sslContext;
}
}
</syntaxhighlight>

=={{header|Julia}}==
<syntaxhighlight lang="julia">using HTTP, MbedTLS

conf = MbedTLS.SSLConfig(true, log_secrets="/utl/secret_key_log.log")
resp = HTTP.get("https://httpbin.org/ip", sslconfig=conf)

println(resp)
</syntaxhighlight>{{output}}<pre>
HTTP.Messages.Response:
"""
HTTP/1.1 200 OK
Connection: keep-alive
Server: gunicorn/19.9.0
Date: Wed, 28 Nov 2018 08:42:25 GMT
Content-Type: application/json
Content-Length: 30
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
Via: 1.1 vegur

{
"origin": "104.28.10.103"
}
"""
</pre>

=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.2.0

import java.security.KeyStore
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.HttpsURLConnection
import java.net.URL
import java.io.FileInputStream
import java.io.InputStreamReader
import java.io.BufferedReader

fun getSSLContext(p12Path: String, password: String): SSLContext {
val ks = KeyStore.getInstance("pkcs12")
val fis = FileInputStream(p12Path)
val pwd = password.toCharArray()
ks.load(fis, pwd)
val kmf = KeyManagerFactory.getInstance("PKIX")
kmf.init(ks, pwd)
val sc = SSLContext.getInstance("TLS")
sc.init(kmf.keyManagers, null, null)
return sc
}

fun main(args: Array<String>) {
// The .p12 file contains the client certificate and private key
val sc = getSSLContext("whatever.p12", "password")
val url = URL("https://somehost.com")
val con = url.openConnection() as HttpsURLConnection
con.sslSocketFactory = sc.socketFactory
val isr = InputStreamReader(con.inputStream)
val br = BufferedReader(isr)
while (true) {
val line = br.readLine()
if (line == null) break
println(line)
}
}</syntaxhighlight>

=={{header|Lasso}}==
<syntaxhighlight lang="lasso">local(sslcert = file('myCert.pem'))
local(x = curl('https://sourceforge.net'))
#x->set(CURLOPT_SSLCERT, #sslcert->readstring)
#sslcert->close
#x->result->asString</syntaxhighlight>

=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">a = RunThrough["curl -E myCert.pem https://www.example.com", 1]
For[ i=0, i < Length[a] , i++, SomeFunction[a]]</syntaxhighlight>

=={{header|Nim}}==
<syntaxhighlight lang="nim">import httpclient, net
var client = newHttpClient(sslContext = newContext(certFile = "mycert.pem"))
var r = client.get("https://www.example.com")</syntaxhighlight>

=={{header|Perl}}==
<syntaxhighlight lang="perl">#!/usr/bin/env perl -T
use 5.018_002;
use warnings;
use LWP;

our $VERSION = 1.000_000;

my $ua = LWP::UserAgent->new(
ssl_opts => {
SSL_cert_file => 'certificate.pem',
SSL_key_file => 'key.pem',
verify_hostname => 1,
}
);
my $req = HTTP::Request->new( GET => 'https://www.example.com' );
my $res = $ua->request($req);
if ( $res->is_success ) {
say $res->content;
}
else {
say $res->status_line;
}</syntaxhighlight>

=={{header|Phix}}==
{{libheader|Phix/libcurl}}
Exactly the same as the HTTP#Phix task, except for the CURLOPT_SSLCERT part.
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">builtins</span><span style="color: #0000FF;">\</span><span style="color: #000000;">libcurl</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
<span style="color: #7060A8;">curl_global_init</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">curl</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">curl_easy_init</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">curl_easy_setopt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">curl</span><span style="color: #0000FF;">,</span> <span style="color: #004600;">CURLOPT_URL</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"https://sourceforge.net"</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">fn</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">open</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"myCert.pem"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"r"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">curl_easy_setopt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">curl</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">CURLOPT_SSLCERT</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">get_text</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">))</span>
<span style="color: #7060A8;">close</span><span style="color: #0000FF;">(</span><span style="color: #000000;">fn</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">res</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">curl_easy_perform_ex</span><span style="color: #0000FF;">(</span><span style="color: #000000;">curl</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">curl_easy_cleanup</span><span style="color: #0000FF;">(</span><span style="color: #000000;">curl</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">curl_global_cleanup</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">res</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->

=={{header|PicoLisp}}==
<syntaxhighlight lang="picolisp">(in '(curl "-E" "myCert.pem" "https://www.example.com")
(while (line)
(doSomeProcessingWithLine @) ) )</syntaxhighlight>

=={{header|Python}}==
<syntaxhighlight lang="python">import httplib

connection = httplib.HTTPSConnection('www.example.com',cert_file='myCert.PEM')
connection.request('GET','/index.html')
response = connection.getresponse()
data = response.read()
</syntaxhighlight>

=={{header|Racket}}==

Skeleton code to connect to a server:
<syntaxhighlight lang="racket">
#lang racket
(require openssl/mzssl)
(define ctx (ssl-make-client-context))
(ssl-set-verify! ctx #t) ; verify the connection
(ssl-load-verify-root-certificates! ctx "my-cert.pem")
(define-values [I O] (ssl-connect "www.example.com" 443 ctx))
</syntaxhighlight>

=={{header|Raku}}==
(formerly Perl 6)
<syntaxhighlight lang="raku" line>
# cert creation commands

# openssl req -newkey rsa:4096 -keyout my_key.pem -out my_csr.pem -nodes -subj "/CN=ME"

# openssl x509 -req -in my_csr.pem -signkey my_key.pem -out my_cert.pem

use v6;
use OpenSSL;

my $host = "github.com";

my $ssl = OpenSSL.new(:client);

$ssl.use-certificate-file("./my_cert.pem");
$ssl.use-privatekey-file("./my_key.pem");
$ssl.check-private-key;


my $s = IO::Socket::INET.new(:$host, :port(443));

$ssl.set-socket($s);
$ssl.set-connect-state;
$ssl.connect;
$ssl.write("GET / HTTP/1.1\r\n\r\n");
say $ssl.read(1024);
$ssl.close;
$s.close;

</syntaxhighlight>

=={{header|Ruby}}==
<syntaxhighlight lang="ruby">require 'uri'
require 'net/http'

uri = URI.parse('https://www.example.com')
pem = File.read("/path/to/my.pem")
cert = OpenSSL::X509::Certificate.new(pem)
key = OpenSSL::PKey::RSA.new(pem)
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
cert: cert, key: key) do |http|
request = Net::HTTP::Get.new uri
http.request request
end</syntaxhighlight>
=={{header|Rust}}==
{{works with|Rust|2021}}
This implementation uses [https://crates.io/crates/reqwest reqwest], the de facto standard high-level HTTP(S) rust library. It is roughly equivalent in purpose and functionality to Python's [https://docs.python-requests.org/en/master/index.html requests].
===Cargo.toml dependencies===
The blocking variant of the reqwest library is used here for simplicity's sake. An asynchronous API is also available.

Native (system) TLS libraries are used instead of Rustls, the Rust TLS implementation, because we use a PKCS#12 certificate which at the time of writing does not seem to be available on Rustls. A PKCS#12 certificate is used instead of its PEM equivalent because reading password-protected PEM files [https://docs.rs/reqwest/0.11.6/reqwest/tls/struct.Identity.html#method.from_pem does not seem to be available] either.
<syntaxhighlight lang="toml">reqwest = {version = "0.11", features = ["native-tls", "blocking"]}</syntaxhighlight>
===src/main.rs===
<syntaxhighlight lang="rust">use std::fs::File;
use std::io::Read;

use reqwest::blocking::Client;
use reqwest::Identity;

fn main() -> std::io::Result<()> {
let identity = {
let mut buf = Vec::new();

// Downloaded from https://badssl.com/certs/badssl.com-client.p12
File::open("badssl.com-client.p12")?.read_to_end(&mut buf)?;

// Password is badssl.com
Identity::from_pkcs12_der(&buf, "badssl.com").unwrap()
};

let client = Client::builder().identity(identity).build().unwrap();
let response = client.get("https://client.badssl.com/").send().unwrap();

if !response.status().is_success() {
eprintln!("HTTP error requesting URL: {}", response.status());
}

println!("Got response from server: {}", response.text().unwrap());

Ok(())
}</syntaxhighlight>

=={{header|Scala}}==
<syntaxhighlight lang="scala">import java.io.FileInputStream
import java.net.URL
import java.security.KeyStore

import javax.net.ssl.{HttpsURLConnection, KeyManagerFactory, SSLContext}

import scala.io.BufferedSource

object ClientAuthenticated extends App {

val con: HttpsURLConnection =
new URL("https://somehost.com").openConnection().asInstanceOf[HttpsURLConnection]

def getSSLContext(p12Path: String, password: String): SSLContext = {
val ks = KeyStore.getInstance("pkcs12")
val pwd = password.toCharArray
ks.load(new FileInputStream(p12Path), pwd)
val kmf = KeyManagerFactory.getInstance("PKIX")
kmf.init(ks, pwd)
val sc = SSLContext.getInstance("TLS")
sc.init(kmf.getKeyManagers, null, null)
sc
}

// The .p12 file contains the client certificate and private key
HttpsURLConnection.setDefaultSSLSocketFactory(getSSLContext("whatever.p12", "password").getSocketFactory)
new BufferedSource(con.getInputStream).getLines.foreach(println(_))

}</syntaxhighlight>


=={{header|Tcl}}==
=={{header|Tcl}}==
Uses the [http://tls.sourceforge.net Tls] package.
Uses the [http://tls.sourceforge.net Tls] package.
<lang tcl>package require http
<syntaxhighlight lang="tcl">package require http
package require tls
package require tls


Line 22: Line 407:
# Now as for conventional use of the “http” package
# Now as for conventional use of the “http” package
set data [http::data $token]
set data [http::data $token]
http::cleanup $token</lang>
http::cleanup $token</syntaxhighlight>

=={{header|Wren}}==
{{libheader|libcurl}}
An embedded program so we can ask the C host to communicate with libcurl for us.
<syntaxhighlight lang="wren">/* HTTPS_Client-authenticated.wren */

var CURLOPT_URL = 10002
var CURLOPT_SSLCERT = 10025
var CURLOPT_SSLKEY = 10087
var CURLOPT_KEYPASSWD = 10258

foreign class Curl {
construct easyInit() {}

foreign easySetOpt(opt, param)

foreign easyPerform()

foreign easyCleanup()
}

var curl = Curl.easyInit()
if (curl == 0) {
System.print("Error initializing cURL.")
return
}

curl.easySetOpt(CURLOPT_URL, "https://example.com/")
curl.easySetOpt(CURLOPT_SSLCERT, "cert.pem")
curl.easySetOpt(CURLOPT_SSLKEY, "key.pem")
curl.easySetOpt(CURLOPT_KEYPASSWD, "s3cret")

var status = curl.easyPerform()
if (status != 0) {
System.print("Failed to perform task.")
return
}
curl.easyCleanup()</syntaxhighlight>
<br>
We now embed this in the following C program, compile and run it.
<syntaxhighlight lang="c">/* gcc HTTPS_Client-authenticated.c -o HTTPS_Client-authenticated -lcurl -lwren -lm */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_curlAllocate(WrenVM* vm) {
CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
*pcurl = curl_easy_init();
}

void C_easyPerform(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLcode cc = curl_easy_perform(curl);
wrenSetSlotDouble(vm, 0, (double)cc);
}

void C_easyCleanup(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
curl_easy_cleanup(curl);
}

void C_easySetOpt(WrenVM* vm) {
CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
const char *arg = wrenGetSlotString(vm, 2);
curl_easy_setopt(curl, opt, arg);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
WrenForeignClassMethods methods;
methods.allocate = NULL;
methods.finalize = NULL;
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Curl") == 0) {
methods.allocate = C_curlAllocate;
}
}
return methods;
}

WrenForeignMethodFn bindForeignMethod(
WrenVM* vm,
const char* module,
const char* className,
bool isStatic,
const char* signature) {
if (strcmp(module, "main") == 0) {
if (strcmp(className, "Curl") == 0) {
if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
if (!isStatic && strcmp(signature, "easyPerform()") == 0) return C_easyPerform;
if (!isStatic && strcmp(signature, "easyCleanup()") == 0) return C_easyCleanup;
}
}
return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
switch (errorType) {
case WREN_ERROR_COMPILE:
printf("[%s line %d] [Error] %s\n", module, line, msg);
break;
case WREN_ERROR_STACK_TRACE:
printf("[%s line %d] in %s\n", module, line, msg);
break;
case WREN_ERROR_RUNTIME:
printf("[Runtime Error] %s\n", msg);
break;
}
}

char *readFile(const char *fileName) {
FILE *f = fopen(fileName, "r");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
rewind(f);
char *script = malloc(fsize + 1);
fread(script, 1, fsize, f);
fclose(f);
script[fsize] = 0;
return script;
}

int main(int argc, char **argv) {
WrenConfiguration config;
wrenInitConfiguration(&config);
config.writeFn = &writeFn;
config.errorFn = &errorFn;
config.bindForeignClassFn = &bindForeignClass;
config.bindForeignMethodFn = &bindForeignMethod;
WrenVM* vm = wrenNewVM(&config);
const char* module = "main";
const char* fileName = "HTTPS_Client-authenticated.wren";
char *script = readFile(fileName);
WrenInterpretResult result = wrenInterpret(vm, module, script);
switch (result) {
case WREN_RESULT_COMPILE_ERROR:
printf("Compile Error!\n");
break;
case WREN_RESULT_RUNTIME_ERROR:
printf("Runtime Error!\n");
break;
case WREN_RESULT_SUCCESS:
break;
}
wrenFreeVM(vm);
free(script);
return 0;
}</syntaxhighlight>

=={{header|zkl}}==
Uses libCurl.
<syntaxhighlight lang="zkl">var CURL=Import("zklCurl"), c=CURL();
c.setOpt("SSLCERT","certFile.pem"); c.setOpt("SSLCERTTYPE","pem");
c.get("http://zenkinetic.com"); // lame example to show how to read</syntaxhighlight>


{{omit from|Batch File|Does not have network access.}}
{{omit from|Batch File|Does not have network access.}}
{{omit from|Brainf***}}
{{omit from|Brainf***}}
{{omit from|Commodore BASIC|Does not have network access}}
{{omit from|EasyLang|Has no internet functions}}
{{omit from|Inform 7|Does not have network access.}}
{{omit from|Inform 7|Does not have network access.}}
{{omit from|Locomotive Basic|Does not have network access.}}
{{omit from|Lotus 123 Macro Scripting}}
{{omit from|Openscad}}
{{omit from|M4}}
{{omit from|M4}}
{{omit from|Maxima}}
{{omit from|ML/I}}
{{omit from|PARI/GP}}
{{omit from|PARI/GP}}
{{omit from|PostScript}}
{{omit from|PostScript}}
{{omit from|Retro|Does not have network access.}}
{{omit from|SQL PL|Does not have network access}}
{{omit from|TI-83 BASIC|Does not have network access.}}
{{omit from|TI-83 BASIC|Does not have network access.}}
{{omit from|TI-89 BASIC|Does not have network access.}}
{{omit from|TI-89 BASIC|Does not have network access.}}

Latest revision as of 10:14, 10 December 2023

Task
HTTPS/Client-authenticated
You are encouraged to solve this task according to the task description, using any language you may know.

Demonstrate how to connect to a web server over HTTPS where that server requires that the client present a certificate to prove who (s)he is. Unlike with the HTTPS request with authentication task, it is not acceptable to perform the authentication by a username/password or a set cookie.

This task is in general useful for use with webservice clients as it offers a high level of assurance that the client is an acceptable counterparty for the server. For example, Amazon Web Services uses this style of authentication.

Arturo

r: request.get.certificate:"mycert.pem" "https://www.example.com" ø

C#

Works with: C sharp version 3.0
using System;
using System.Net;

class Program
{
    class MyWebClient : WebClient
    {
        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(address);
            request.ClientCertificates.Add(new X509Certificate());
            return request;
        }
    }
    static void Main(string[] args)
    {
        var client = new MyWebClient();

        var data = client.DownloadString("https://example.com");

        Console.WriteLine(data);
    }
}

Go

package main

import (
	"crypto/tls"
	"io/ioutil"
	"log"
	"net/http"
)

func main() {

	// load key pair
	cert, err := tls.LoadX509KeyPair(
		"./client.local.tld/client.local.tld.crt",
		"./client.local.tld/client.local.tld.key",
	)

	if err != nil {
		log.Fatal("Error while loading x509 key pair", err)
	}

	// Create TLS Config in order to had client certificate
	tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}

	tlsConfig.BuildNameToCertificate()
	transport := &http.Transport{TLSClientConfig: tlsConfig}

	// create http client with our custom transport with TLS config
	client := &http.Client{Transport: transport}

	res, err := client.Get("https://www.example.com/")
	if err != nil {
		log.Fatal(err)
	}
	contents, err := ioutil.ReadAll(res.Body)
	log.Print(string(contents))

}

Java

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.net.URI;
import java.net.URL;
import java.security.KeyStore;
import java.util.Scanner;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

public final class HTTPSClientAuthenticated {

	public static void main(String[] aArgs) throws Exception {
		final String keyStorePath = "the/path/to/keystore"; // The key store contains the client's certificate
		final String keyStorePassword = "my-password";
		
	    SSLContext sslContext = getSSLContext(keyStorePath, keyStorePassword);
	    URL url = new URI("https://somehost.com").toURL();
	    HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
	    connection.setSSLSocketFactory(sslContext.getSocketFactory());	    
	    
	    // Obtain response from the url
	    BufferedInputStream response = (BufferedInputStream) connection.getInputStream();
	    try ( Scanner scanner = new Scanner(response) ) {
	        String responseBody = scanner.useDelimiter("\\A").next();
	        System.out.println(responseBody);
	    }	    
	}
	
	private static SSLContext getSSLContext(String aPath, String aPassword) throws Exception {
	    KeyStore keyStore = KeyStore.getInstance("pkcs12");
	    keyStore.load( new FileInputStream(aPath), aPassword.toCharArray());
	    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
	    keyManagerFactory.init(keyStore, aPassword.toCharArray());
	    SSLContext sslContext = SSLContext.getInstance("TLS");
	    sslContext.init(keyManagerFactory.getKeyManagers(), null, null);
	    return sslContext;
	} 
	
}

Julia

using HTTP, MbedTLS

conf = MbedTLS.SSLConfig(true, log_secrets="/utl/secret_key_log.log")
resp = HTTP.get("https://httpbin.org/ip", sslconfig=conf)

println(resp)
Output:

HTTP.Messages.Response: """ HTTP/1.1 200 OK Connection: keep-alive Server: gunicorn/19.9.0 Date: Wed, 28 Nov 2018 08:42:25 GMT Content-Type: application/json Content-Length: 30 Access-Control-Allow-Origin: * Access-Control-Allow-Credentials: true Via: 1.1 vegur

{

 "origin": "104.28.10.103"

} """

Kotlin

// version 1.2.0

import java.security.KeyStore
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.HttpsURLConnection
import java.net.URL
import java.io.FileInputStream
import java.io.InputStreamReader
import java.io.BufferedReader

fun getSSLContext(p12Path: String, password: String): SSLContext {
    val ks = KeyStore.getInstance("pkcs12")
    val fis = FileInputStream(p12Path)
    val pwd = password.toCharArray()
    ks.load(fis, pwd)
    val kmf = KeyManagerFactory.getInstance("PKIX")
    kmf.init(ks, pwd)
    val sc = SSLContext.getInstance("TLS")
    sc.init(kmf.keyManagers, null, null)
    return sc
}

fun main(args: Array<String>) {
    // The .p12 file contains the client certificate and private key
    val sc = getSSLContext("whatever.p12", "password")
    val url = URL("https://somehost.com")
    val con = url.openConnection() as HttpsURLConnection
    con.sslSocketFactory = sc.socketFactory
    val isr = InputStreamReader(con.inputStream)
    val br = BufferedReader(isr)
    while (true) {
        val line = br.readLine()
        if (line == null) break
        println(line)
    }
}

Lasso

local(sslcert = file('myCert.pem'))
local(x = curl('https://sourceforge.net'))
#x->set(CURLOPT_SSLCERT, #sslcert->readstring)
#sslcert->close
#x->result->asString

Mathematica / Wolfram Language

a = RunThrough["curl -E myCert.pem https://www.example.com", 1]
For[ i=0, i < Length[a] , i++, SomeFunction[a]]

Nim

import httpclient, net
var client = newHttpClient(sslContext = newContext(certFile = "mycert.pem"))
var r = client.get("https://www.example.com")

Perl

#!/usr/bin/env perl -T
use 5.018_002;
use warnings;
use LWP;

our $VERSION = 1.000_000;

my $ua = LWP::UserAgent->new(
    ssl_opts => {
        SSL_cert_file   => 'certificate.pem',
        SSL_key_file    => 'key.pem',
        verify_hostname => 1,
    }
);
my $req = HTTP::Request->new( GET => 'https://www.example.com' );
my $res = $ua->request($req);
if ( $res->is_success ) {
    say $res->content;
}
else {
    say $res->status_line;
}

Phix

Library: Phix/libcurl

Exactly the same as the HTTP#Phix task, except for the CURLOPT_SSLCERT part.

without js
include builtins\libcurl.e
curl_global_init()
atom curl = curl_easy_init()
curl_easy_setopt(curl, CURLOPT_URL, "https://sourceforge.net")
integer fn = open("myCert.pem","r")
curl_easy_setopt(curl, CURLOPT_SSLCERT, get_text(fn))
close(fn)
object res = curl_easy_perform_ex(curl)
curl_easy_cleanup(curl)
curl_global_cleanup()
 
puts(1,res)

PicoLisp

(in '(curl "-E" "myCert.pem" "https://www.example.com")
   (while (line)
      (doSomeProcessingWithLine @) ) )

Python

import httplib

connection = httplib.HTTPSConnection('www.example.com',cert_file='myCert.PEM')
connection.request('GET','/index.html')
response = connection.getresponse()
data = response.read()

Racket

Skeleton code to connect to a server:

#lang racket
(require openssl/mzssl)
(define ctx (ssl-make-client-context))
(ssl-set-verify! ctx #t) ; verify the connection
(ssl-load-verify-root-certificates! ctx "my-cert.pem")
(define-values [I O] (ssl-connect "www.example.com" 443 ctx))

Raku

(formerly Perl 6)

# cert creation commands

# openssl req -newkey rsa:4096 -keyout my_key.pem -out my_csr.pem -nodes -subj "/CN=ME"

# openssl x509 -req -in my_csr.pem -signkey my_key.pem -out my_cert.pem

use v6;
use OpenSSL;

my $host = "github.com";

my $ssl = OpenSSL.new(:client);

$ssl.use-certificate-file("./my_cert.pem");
$ssl.use-privatekey-file("./my_key.pem");
$ssl.check-private-key;


my $s = IO::Socket::INET.new(:$host, :port(443));

$ssl.set-socket($s);
$ssl.set-connect-state;
$ssl.connect;
$ssl.write("GET / HTTP/1.1\r\n\r\n");
say $ssl.read(1024);
$ssl.close;
$s.close;

Ruby

require 'uri'
require 'net/http'

uri = URI.parse('https://www.example.com')
pem = File.read("/path/to/my.pem")
cert = OpenSSL::X509::Certificate.new(pem)
key = OpenSSL::PKey::RSA.new(pem)
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true,
                           cert: cert, key: key) do |http|
  request = Net::HTTP::Get.new uri
  http.request request
end

Rust

Works with: Rust version 2021

This implementation uses reqwest, the de facto standard high-level HTTP(S) rust library. It is roughly equivalent in purpose and functionality to Python's requests.

Cargo.toml dependencies

The blocking variant of the reqwest library is used here for simplicity's sake. An asynchronous API is also available.

Native (system) TLS libraries are used instead of Rustls, the Rust TLS implementation, because we use a PKCS#12 certificate which at the time of writing does not seem to be available on Rustls. A PKCS#12 certificate is used instead of its PEM equivalent because reading password-protected PEM files does not seem to be available either.

reqwest = {version = "0.11", features = ["native-tls", "blocking"]}

src/main.rs

use std::fs::File;
use std::io::Read;

use reqwest::blocking::Client;
use reqwest::Identity;

fn main() -> std::io::Result<()> {
    let identity = {
        let mut buf = Vec::new();

        // Downloaded from https://badssl.com/certs/badssl.com-client.p12
        File::open("badssl.com-client.p12")?.read_to_end(&mut buf)?;

        // Password is badssl.com
        Identity::from_pkcs12_der(&buf, "badssl.com").unwrap()
    };

    let client = Client::builder().identity(identity).build().unwrap();
    let response = client.get("https://client.badssl.com/").send().unwrap();

    if !response.status().is_success() {
        eprintln!("HTTP error requesting URL: {}", response.status());
    }

    println!("Got response from server: {}", response.text().unwrap());

    Ok(())
}

Scala

import java.io.FileInputStream
import java.net.URL
import java.security.KeyStore

import javax.net.ssl.{HttpsURLConnection, KeyManagerFactory, SSLContext}

import scala.io.BufferedSource

object ClientAuthenticated extends App {

  val con: HttpsURLConnection =
    new URL("https://somehost.com").openConnection().asInstanceOf[HttpsURLConnection]

  def getSSLContext(p12Path: String, password: String): SSLContext = {
    val ks = KeyStore.getInstance("pkcs12")
    val pwd = password.toCharArray
    ks.load(new FileInputStream(p12Path), pwd)
    val kmf = KeyManagerFactory.getInstance("PKIX")
    kmf.init(ks, pwd)
    val sc = SSLContext.getInstance("TLS")
    sc.init(kmf.getKeyManagers, null, null)
    sc
  }

  // The .p12 file contains the client certificate and private key
  HttpsURLConnection.setDefaultSSLSocketFactory(getSSLContext("whatever.p12", "password").getSocketFactory)
  new BufferedSource(con.getInputStream).getLines.foreach(println(_))

}

Tcl

Uses the Tls package.

package require http
package require tls

set cert myCert.p12
http::register https 443 [list \
    ::tls::socket -certfile $cert -password getPass]
proc getPass {} {
    return "myPassword";  # Just a noddy example...
} 

# Make a secure authenticated connection
set token [http::geturl https://verysecure.example.com/]
 
# Now as for conventional use of the “http” package
set data [http::data $token]
http::cleanup $token

Wren

Library: libcurl

An embedded program so we can ask the C host to communicate with libcurl for us.

/* HTTPS_Client-authenticated.wren */

var CURLOPT_URL       = 10002
var CURLOPT_SSLCERT   = 10025
var CURLOPT_SSLKEY    = 10087
var CURLOPT_KEYPASSWD = 10258

foreign class Curl {
    construct easyInit() {}

    foreign easySetOpt(opt, param)

    foreign easyPerform()

    foreign easyCleanup()
}

var curl = Curl.easyInit()
if (curl == 0) {
    System.print("Error initializing cURL.")
    return
}

curl.easySetOpt(CURLOPT_URL, "https://example.com/")
curl.easySetOpt(CURLOPT_SSLCERT, "cert.pem")
curl.easySetOpt(CURLOPT_SSLKEY, "key.pem")
curl.easySetOpt(CURLOPT_KEYPASSWD, "s3cret")

var status = curl.easyPerform()
if (status != 0) {
    System.print("Failed to perform task.")
    return
}
curl.easyCleanup()


We now embed this in the following C program, compile and run it.

/* gcc HTTPS_Client-authenticated.c -o HTTPS_Client-authenticated -lcurl -lwren -lm  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "wren.h"

/* C <=> Wren interface functions */

void C_curlAllocate(WrenVM* vm) {
    CURL** pcurl = (CURL**)wrenSetSlotNewForeign(vm, 0, 0, sizeof(CURL*));
    *pcurl = curl_easy_init();
}

void C_easyPerform(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    CURLcode cc = curl_easy_perform(curl);
    wrenSetSlotDouble(vm, 0, (double)cc);
}

void C_easyCleanup(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    curl_easy_cleanup(curl);
}

void C_easySetOpt(WrenVM* vm) {
    CURL* curl = *(CURL**)wrenGetSlotForeign(vm, 0);
    CURLoption opt = (CURLoption)wrenGetSlotDouble(vm, 1);
    const char *arg = wrenGetSlotString(vm, 2);
    curl_easy_setopt(curl, opt, arg);
}

WrenForeignClassMethods bindForeignClass(WrenVM* vm, const char* module, const char* className) {
    WrenForeignClassMethods methods;
    methods.allocate = NULL;
    methods.finalize = NULL;
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "Curl") == 0) {
            methods.allocate = C_curlAllocate;
        }
    }
    return methods;
}

WrenForeignMethodFn bindForeignMethod(
    WrenVM* vm,
    const char* module,
    const char* className,
    bool isStatic,
    const char* signature) {
    if (strcmp(module, "main") == 0) {
        if (strcmp(className, "Curl") == 0) {
            if (!isStatic && strcmp(signature, "easySetOpt(_,_)") == 0) return C_easySetOpt;
            if (!isStatic && strcmp(signature, "easyPerform()") == 0)   return C_easyPerform;
            if (!isStatic && strcmp(signature, "easyCleanup()") == 0)   return C_easyCleanup;
        }
    }
    return NULL;
}

static void writeFn(WrenVM* vm, const char* text) {
    printf("%s", text);
}

void errorFn(WrenVM* vm, WrenErrorType errorType, const char* module, const int line, const char* msg) {
    switch (errorType) {
        case WREN_ERROR_COMPILE:
            printf("[%s line %d] [Error] %s\n", module, line, msg);
            break;
        case WREN_ERROR_STACK_TRACE:
            printf("[%s line %d] in %s\n", module, line, msg);
            break;
        case WREN_ERROR_RUNTIME:
            printf("[Runtime Error] %s\n", msg);
            break;
    }
}

char *readFile(const char *fileName) {
    FILE *f = fopen(fileName, "r");
    fseek(f, 0, SEEK_END);
    long fsize = ftell(f);
    rewind(f);
    char *script = malloc(fsize + 1);
    fread(script, 1, fsize, f);
    fclose(f);
    script[fsize] = 0;
    return script;
}

int main(int argc, char **argv) {
    WrenConfiguration config;
    wrenInitConfiguration(&config);
    config.writeFn = &writeFn;
    config.errorFn = &errorFn;
    config.bindForeignClassFn = &bindForeignClass;
    config.bindForeignMethodFn = &bindForeignMethod;
    WrenVM* vm = wrenNewVM(&config);
    const char* module = "main";
    const char* fileName = "HTTPS_Client-authenticated.wren";
    char *script = readFile(fileName);
    WrenInterpretResult result = wrenInterpret(vm, module, script);
    switch (result) {
        case WREN_RESULT_COMPILE_ERROR:
            printf("Compile Error!\n");
            break;
        case WREN_RESULT_RUNTIME_ERROR:
            printf("Runtime Error!\n");
            break;
        case WREN_RESULT_SUCCESS:
            break;
    }
    wrenFreeVM(vm);
    free(script);
    return 0;
}

zkl

Uses libCurl.

var CURL=Import("zklCurl"), c=CURL();
c.setOpt("SSLCERT","certFile.pem"); c.setOpt("SSLCERTTYPE","pem");
c.get("http://zenkinetic.com");  // lame example to show how to read