HTTPS/Client-authenticated: Difference between revisions
(Added Wren) |
m (→{{header|Wren}}: Removed trans template as not applicable here.) |
||
Line 320: | Line 320: | ||
=={{header|Wren}}== |
=={{header|Wren}}== |
||
{{trans|C}} |
|||
{{libheader|libcurl}} |
{{libheader|libcurl}} |
||
An embedded program so we can ask the C host to communicate with libcurl for us. |
An embedded program so we can ask the C host to communicate with libcurl for us. |
Revision as of 17:55, 5 October 2021
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.
C#
<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); }
} </lang>
Go
<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))
} </lang>
Julia
<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)
</lang>
- 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
<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) }
}</lang>
Lasso
<lang Lasso>local(sslcert = file('myCert.pem')) local(x = curl('https://sourceforge.net'))
- x->set(CURLOPT_SSLCERT, #sslcert->readstring)
- sslcert->close
- x->result->asString</lang>
Mathematica / Wolfram Language
<lang Mathematica>a = RunThrough["curl -E myCert.pem https://www.example.com", 1] For[ i=0, i < Length[a] , i++, SomeFunction[a]]</lang>
Nim
<lang nim>import httpclient, net var client = newHttpClient(sslContext = newContext(certFile = "mycert.pem")) var r = client.get("https://www.example.com")</lang>
Perl
<lang python>#!/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;
}</lang>
Phix
Exactly the same as the HTTP#Phix task, except for the CURLOPT_SSLCERT part. <lang Phix>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)</lang>
PicoLisp
<lang PicoLisp>(in '(curl "-E" "myCert.pem" "https://www.example.com")
(while (line) (doSomeProcessingWithLine @) ) )</lang>
Python
<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() </lang>
Racket
Skeleton code to connect to a server: <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)) </lang>
Raku
(formerly Perl 6) <lang perl6>
- 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;
</lang>
Ruby
<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</lang>
Scala
<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(_))
}</lang>
Tcl
Uses the Tls package. <lang tcl>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</lang>
Wren
An embedded program so we can ask the C host to communicate with libcurl for us. <lang ecmascript>/* 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()</lang>
We now embed this in the following C program, compile and run it.
<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;
}</lang>
zkl
Uses libCurl. <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</lang>
- Programming Tasks
- Programming environment operations
- Networking and Web Interaction
- C sharp
- Go
- Julia
- Kotlin
- Lasso
- Mathematica
- Wolfram Language
- Nim
- Perl
- Phix
- Phix/libcurl
- PicoLisp
- Python
- Racket
- Raku
- Ruby
- Scala
- Tcl
- Wren
- Libcurl
- Zkl
- Batch File/Omit
- Brainf***/Omit
- Commodore BASIC/Omit
- Inform 7/Omit
- Locomotive Basic/Omit
- Lotus 123 Macro Scripting/Omit
- Openscad/Omit
- M4/Omit
- Maxima/Omit
- ML/I/Omit
- PARI/GP/Omit
- PostScript/Omit
- Retro/Omit
- SQL PL/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Unlambda/Omit
- Yorick/Omit
- ZX Spectrum Basic/Omit