EST 7030
TL;DR: Enrollment over Secure Transport.
Вступ

Центр сертифікації ключів SYNRC CA/EST
ASN.1 специфікація на модель даних і регламент взаємодії
~/home/synrc/ca/priv/csr/:
AlgorithmInformation-2009.asn1
AuthenticationFramework.asn1
BasicAccessControl.asn1
CertificateExtensions.asn1
CryptographicMessageSyntax-2009.asn1
CryptographicMessageSyntaxAlgorithms-2009.asn1
DirectoryAbstractService.asn1
EST.asn1
EnrollmentMessageSyntax-2009.asn1
InformationFramework.asn1
PKCS-10.asn1
PKIX-CommonTypes-2009.asn1
PKIX-X400Address-2009.asn1
PKIX1-PSS-OAEP-Algorithms-2009.asn1
PKIX1Explicit-2009.asn1
PKIX1Implicit-2009.asn1
PKIXAlgs-2009.asn1
SecureMimeMessageV3dot1-2009.asn1
SelectedAttributeTypes.asn1
UpperBounds.asn1
UsefulDefinitions.asn1
ANSI-X9-42.asn1
ANSI-X9-62.asn1
KEP.asn1
DSTU.asn1
OCSP.asn1
LDAP.asn1
CHAT.asn1
EST DEFINITIONS IMPLICIT TAGS ::= BEGIN
IMPORTS AttributeSet{}, Extension{}, EXTENSION, ATTRIBUTE FROM PKIX-CommonTypes-2009
CertExtensions FROM PKIX1Implicit-2009 ;
Int ::= INTEGER
OID ::= OBJECT IDENTIFIER
CsrAttrs ::= SEQUENCE OF AttrOrOID
AttrOrOID ::= CHOICE { oid OBJECT IDENTIFIER, attribute Attribute }
Attribute ::= SEQUENCE { type ATTRIBUTE.&id, values SET SIZE(1..MAX) OF ATTRIBUTE.&Type }
Extension ::= SEQUENCE { extnId EXTENSION.&id, critical BOOLEAN DEFAULT FALSE, extnValue EXTENSION.&ExtnType }
ExtensionReq ::= SEQUENCE SIZE (1..MAX) OF Extension{{CertExtensions}}
at-extension-req ATTRIBUTE ::= { TYPE ExtensionReq IDENTIFIED BY id-ExtensionReq }
id-ExtensionReq OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9) 14}
END
Дерево файлів
~/home/synrc/ca/:
├── openssl/
├── arvo/
├── synrc/
├── config/
├── include/
├── lib/
├── man/
├── priv/
├── src/
├── CNAME
├── LICENSE
├── README.md
└── mix.exs
~/home/synrc/ca/lib/:
├── application.ex
├── agreement
│ ├── EC
│ │ ├── curve.ex
│ │ ├── integer.ex
│ │ ├── jacobian.ex
│ │ └── point.ex
│ └── ecc.ex
├── derivation
│ ├── hkdf.ex
│ └── kdf.ex
├── encryption
│ ├── aes.ex
│ └── cms.ex
├── oid
│ ├── alg.ex
│ ├── at.ex
│ ├── ce.ex
│ ├── kp.ex
│ ├── nis.ex
│ └── x962.ex
├── services
│ ├── cmc.ex
│ ├── cmp.ex
│ ├── csr.ex
│ ├── est.ex
│ ├── http
│ │ ├── get.ex
│ │ └── post.ex
│ ├── ocsp.ex
│ └── tsp.ex
└── signing
├── CAdES.ex
├── ecdsa.ex
└── ecdsa_otp.ex
Опис пакету
defmodule CA.Mixfile do
use Mix.Project
def application(), do: [ mod: {CA, []}, extra_applications: [:x509, :bandit, :plug]]
def project() do
[
app: :ca,
version: "5.10.4",
description: "CA CXC 138 21 Certificate Authority",
package: [
name: :ca,
files: ~w(config src include priv lib mix.exs LICENSE README.md),
licenses: ["ISC"],
maintainers: ["Namdak Tonpa"],
links: %{"GitHub" => "https://github.com/synrc/ca"}
],
deps: [
{:jason, "~> 1.2"},
{:plug, "~> 1.15.3"},
{:bandit, "~> 1.0"},
{:ex_doc, ">= 0.0.0", only: :dev},
{:x509, "~> 0.8.7"}
]
]
end
end
Регламент взаємодії
GET /.well-known/est/ca
def get(conn, [], "Authority", [], "CA") do
body = :base64.encode(CA.CSR.read_ca_public())
conn |> put_resp_content_type("application/pkix-cert")
|> put_resp_header("Content-Transfer-Encoding", "base64")
|> put_resp_header("Content-Length", Integer.to_string(byte_size(body)))
|> resp(200, body)
|> send_resp()
end
def read_ca_public() do
{:ok, ca_bin} = :file.read_file "ca.pem"
{:ok, ca} = X509.Certificate.from_pem ca_bin
{:ok, bin} = :"PKIX1Explicit-2009".encode(:Certificate, CA.CMP.convertOTPtoPKIX(ca))
bin
end
GET /.well-known/est/cacerts
def get(conn, [], "Authority", [], "CMS") do
ca = CA.CSR.read_ca_public()
{:ok, cacert} = :"PKIX1Explicit-2009".decode(:Certificate, ca)
ci = {:ContentInfo, {1, 2, 840, 113549, 1, 7, 2},
{:SignedData, :v1, [],
{:EncapsulatedContentInfo, {1, 2, 840, 113549, 1, 7, 1}, :asn1_NOVALUE},
[certificate: cacert], [], []}}
{:ok, cms} = :"CryptographicMessageSyntax-2010".encode :ContentInfo, ci
body = :base64.encode cms
conn |> put_resp_content_type("application/pkcs7-mime")
|> put_resp_header("Content-Transfer-Encoding", "base64")
|> put_resp_header("Content-Length", Integer.to_string(byte_size(body)))
|> resp(200, body)
|> send_resp()
end
GET /.well-known/est/csrattrs
def get(conn, [], "Authority", [], "ABAC") do
body = :base64.encode(CA.EST.csrattributes())
conn |> put_resp_content_type("application/csrattrs")
|> put_resp_header("Content-Transfer-Encoding", "base64")
|> put_resp_header("Content-Length", Integer.to_string(byte_size(body)))
|> resp(200, body)
|> send_resp()
end
def csrattributes() do
{:ok, bin} = :"EST".encode(:CsrAttrs, [
oid: CA.AT.oid(:"id-at-challengePassword"),
oid: CA.X962.oid(:"id-ds-ecdsa-with-SHA384"),
attribute: {:Attribute, CA.X962.oid(:"id-kt-ecPublicKey"), [objectIdentifier(CA.ALG.oid(:secp384r1))] },
attribute: {:Attribute, CA.AT.oid(:"id-at-rsaEncryption"), [integer(4096)]},
attribute: {:Attribute, CA.AT.oid(:"id-at-extensionRequest"), [
extension({:Extension, CA.CE.oid(:"id-ce-keyUsage"), true, keyUsage([:digitalSignature, :keyCertSign, :cRLSign])}),
extension({:Extension, CA.CE.oid(:"id-ce-basicConstraints"), true, basicConstraints()}),
extension({:Extension, CA.CE.oid(:"id-ce-extKeyUsage"), false,
extendedKeyUsage([ CA.KP.oid(:"id-kp-serverAuth"),
CA.KP.oid(:"id-kp-clientAuth"),
CA.KP.oid(:"id-kp-codeSigning"),
CA.KP.oid(:"id-kp-emailProtection") ])})
]}
])
bin
end
POST /.well-known/est/simpleenroll
POST /.well-known/est/simplereenroll
POST /.well-known/est/serverkeygen
POST /.well-known/est/fullcmc
Реквізити для ABAC
Додаток 1. Атрибути PKCS-10 CSR запиту
defmodule CA.AT do
@moduledoc "CA CSR Attributes OIDs."
def oid(:"id-at-rsaEncryption"), do: {1, 2, 840, 113549, 1, 1, 1}
def oid(:"id-at-sha1WithRSAEncryption"), do: {1, 2, 840, 113549, 1, 1, 5}
def oid(:"id-at-sha512-256WithRSAEncryption"), do: {1, 2, 840, 113549, 1, 1, 16}
def oid(:"id-at-dhKeyAgreement"), do: {1, 2, 840, 113549, 1, 3, 1}
def oid(:"id-at-emailAddress"), do: {1, 2, 840, 113549, 1, 9, 1}
def oid(:"id-at-unstructuredName"), do: {1, 2, 840, 113549, 1, 9, 2}
def oid(:"id-at-contentType"), do: {1, 2, 840, 113549, 1, 9, 3}
def oid(:"id-at-messageDigest"), do: {1, 2, 840, 113549, 1, 9, 4}
def oid(:"id-at-signingTime"), do: {1, 2, 840, 113549, 1, 9, 5}
def oid(:"id-at-counterSignature"), do: {1, 2, 840, 113549, 1, 9, 6}
def oid(:"id-at-challengePassword"), do: {1, 2, 840, 113549, 1, 9, 7}
def oid(:"id-at-unstructuredAddress"), do: {1, 2, 840, 113549, 1, 9, 8}
def oid(:"id-at-extendedCertificateAttributes"), do: {1, 2, 840, 113549, 1, 9, 9}
def oid(:"id-at-issuerAndSerialNumber"), do: {1, 2, 840, 113549, 1, 9, 10}
def oid(:"id-at-passwordCheck"), do: {1, 2, 840, 113549, 1, 9, 11}
def oid(:"id-at-publicKey"), do: {1, 2, 840, 113549, 1, 9, 12}
def oid(:"id-at-signingDescription"), do: {1, 2, 840, 113549, 1, 9, 13}
def oid(:"id-at-extensionRequest"), do: {1, 2, 840, 113549, 1, 9, 14}
def oid(:"id-at-smimeCapabilities"), do: {1, 2, 840, 113549, 1, 9, 15}
Додаток 2. Розширення сертифікату
defmodule CA.CE do
@moduledoc "CA Certificate Extensions OIDs."
def oid(:"id-ce-subjectDirectoryAttributes"), do: {2, 5, 29, 9}
def oid(:"id-ce-subjectKeyIdentifier"), do: {2, 5, 29, 14}
def oid(:"id-ce-keyUsage"), do: {2, 5, 29, 15}
def oid(:"id-ce-privateKeyUsagePeriod"), do: {2, 5, 29, 16}
def oid(:"id-ce-subjectAltName"), do: {2, 5, 29, 17}
def oid(:"id-ce-issuerAltName"), do: {2, 5, 29, 18}
def oid(:"id-ce-basicConstraints"), do: {2, 5, 29, 19}
def oid(:"id-ce-cRLNumber"), do: {2, 5, 29, 20}
def oid(:"id-ce-reasonCode"), do: {2, 5, 29, 21}
def oid(:"id-ce-expirationDate"), do: {2, 5, 29, 22}
def oid(:"id-ce-holdInstructionCode"), do: {2, 5, 29, 23}
def oid(:"id-ce-invalidityDate"), do: {2, 5, 29, 24}
def oid(:"id-ce-deltaCRLIndicator"), do: {2, 5, 29, 27}
def oid(:"id-ce-issuingDistributionPoint"), do: {2, 5, 29, 28}
def oid(:"id-ce-certificateIssuer"), do: {2, 5, 29, 29}
def oid(:"id-ce-nameConstraints"), do: {2, 5, 29, 30}
def oid(:"id-ce-cRLDistributionPoints"), do: {2, 5, 29, 31}
def oid(:"id-ce-certificatePolicies"), do: {2, 5, 29, 32}
def oid(:"id-ce-policyMappings"), do: {2, 5, 29, 33}
def oid(:"id-ce-authorityKeyIdentifier"), do: {2, 5, 29, 35}
def oid(:"id-ce-policyConstraints"), do: {2, 5, 29, 36}
def oid(:"id-ce-extKeyUsage"), do: {2, 5, 29, 37}
def oid(:"id-ce-authorityAttributeIdentifier"), do: {2, 5, 29, 38}
def oid(:"id-ce-roleSpecCertIdentifier"), do: {2, 5, 29, 39}
def oid(:"id-ce-cRLStreamIdentifier"), do: {2, 5, 29, 40}
def oid(:"id-ce-basicAttConstraints"), do: {2, 5, 29, 41}
def oid(:"id-ce-delegatedNameConstraints"), do: {2, 5, 29, 42}
def oid(:"id-ce-timeSpecification"), do: {2, 5, 29, 43}
def oid(:"id-ce-crlScope"), do: {2, 5, 29, 44}
def oid(:"id-ce-statusReferrals"), do: {2, 5, 29, 45}
def oid(:"id-ce-freshestCRL"), do: {2, 5, 29, 46}
def oid(:"id-ce-orderedList"), do: {2, 5, 29, 47}
def oid(:"id-ce-attributeDescriptor"), do: {2, 5, 29, 48}
def oid(:"id-ce-userNotice"), do: {2, 5, 29, 49}
def oid(:"id-ce-sOAIdentifier"), do: {2, 5, 29, 50}
def oid(:"id-ce-baseUpdateTime"), do: {2, 5, 29, 51}
def oid(:"id-ce-acceptableCertPolicies"), do: {2, 5, 29, 52}
def oid(:"id-ce-deltaInfo"), do: {2, 5, 29, 53}
def oid(:"id-ce-inhibitAnyPolicy"), do: {2, 5, 29, 54}
def oid(:"id-ce-targetingInformation"), do: {2, 5, 29, 55}
def oid(:"id-ce-noRevAvail"), do: {2, 5, 29, 56}
def oid(:"id-ce-acceptablePrivilegePolicies"), do: {2, 5, 29, 57}
def oid(:"id-ce-toBeRevoked"), do: {2, 5, 29, 58}
def oid(:"id-ce-revokedGroups"), do: {2, 5, 29, 59}
def oid(:"id-ce-expiredCertsOnCRL"), do: {2, 5, 29, 60}
def oid(:"id-ce-indirectIssuer"), do: {2, 5, 29, 61}
def oid(:"id-ce-noAssertion"), do: {2, 5, 29, 62}
def oid(:"id-ce-aAissuingDistributionPoint"), do: {2, 5, 29, 63}
def oid(:"id-ce-issuedOnBehalfOf"), do: {2, 5, 29, 64}
def oid(:"id-ce-singleUse"), do: {2, 5, 29, 65}
def oid(:"id-ce-groupAC"), do: {2, 5, 29, 66}
def oid(:"id-ce-allowedAttributeAssignments"), do: {2, 5, 29, 67}
def oid(:"id-ce-attributeMappings"), do: {2, 5, 29, 68}
def oid(:"id-ce-holderNameConstraints"), do: {2, 5, 29, 69}
def oid(:"id-ce-authorizationValidation"), do: {2, 5, 29, 70}
def oid(:"id-ce-protRestrict"), do: {2, 5, 29, 71}
def oid(:"id-ce-subjectAltPublicKeyInfo"), do: {2, 5, 29, 72}
def oid(:"id-ce-altSignatureAlgorithm"), do: {2, 5, 29, 73}
def oid(:"id-ce-altSignatureValue"), do: {2, 5, 29, 74}
def oid(:"id-ce-associatedInformation"), do: {2, 5, 29, 75}
Додаток 3. Призначення ключів сертифікатів
module CA.KP do
@moduledoc "CA Key Purpose OIDs."
def oid(:"id-kp-serverAuth"), do: {1, 3, 6, 1, 5, 5, 7, 3, 1}
def oid(:"id-kp-clientAuth"), do: {1, 3, 6, 1, 5, 5, 7, 3, 2}
def oid(:"id-kp-codeSigning"), do: {1, 3, 6, 1, 5, 5, 7, 3, 3}
def oid(:"id-kp-emailProtection"), do: {1, 3, 6, 1, 5, 5, 7, 3, 4}
def oid(:"id-kp-ipsecEndSystem"), do: {1, 3, 6, 1, 5, 5, 7, 3, 5}
def oid(:"id-kp-ipsecTunnel"), do: {1, 3, 6, 1, 5, 5, 7, 3, 6}
def oid(:"id-kp-ipsecUser"), do: {1, 3, 6, 1, 5, 5, 7, 3, 7}
def oid(:"id-kp-timeStamping"), do: {1, 3, 6, 1, 5, 5, 7, 3, 8}
def oid(:"id-kp-OCSPSigning"), do: {1, 3, 6, 1, 5, 5, 7, 3, 9}
def oid(:"id-kp-dvcs"), do: {1, 3, 6, 1, 5, 5, 7, 3, 10}
def oid(:"id-kp-sbgpCertAAServerAuth"), do: {1, 3, 6, 1, 5, 5, 7, 3, 11}
def oid(:"id-kp-scvp-responder"), do: {1, 3, 6, 1, 5, 5, 7, 3, 12}
def oid(:"id-kp-eapOverPPP"), do: {1, 3, 6, 1, 5, 5, 7, 3, 13}
def oid(:"id-kp-eapOverLAN"), do: {1, 3, 6, 1, 5, 5, 7, 3, 14}
def oid(:"id-kp-scvpServer"), do: {1, 3, 6, 1, 5, 5, 7, 3, 15}
def oid(:"id-kp-scvpClient"), do: {1, 3, 6, 1, 5, 5, 7, 3, 16}
def oid(:"id-kp-ipsecIKE"), do: {1, 3, 6, 1, 5, 5, 7, 3, 17}
def oid(:"id-kp-capwapAC"), do: {1, 3, 6, 1, 5, 5, 7, 3, 18}
def oid(:"id-kp-capwapWTP"), do: {1, 3, 6, 1, 5, 5, 7, 3, 19}
def oid(:"id-kp-sipDomain"), do: {1, 3, 6, 1, 5, 5, 7, 3, 20}
def oid(:"id-kp-secureShellClient"), do: {1, 3, 6, 1, 5, 5, 7, 3, 21}
def oid(:"id-kp-secureShellServer"), do: {1, 3, 6, 1, 5, 5, 7, 3, 22}
def oid(:"id-kp-sendRouter"), do: {1, 3, 6, 1, 5, 5, 7, 3, 23}
def oid(:"id-kp-sendProxiedRouter"), do: {1, 3, 6, 1, 5, 5, 7, 3, 24}
def oid(:"id-kp-sendOwner"), do: {1, 3, 6, 1, 5, 5, 7, 3, 25}
def oid(:"id-kp-sendProxiedOwner"), do: {1, 3, 6, 1, 5, 5, 7, 3, 26}
def oid(:"id-kp-cmcCA"), do: {1, 3, 6, 1, 5, 5, 7, 3, 27}
def oid(:"id-kp-cmcRA"), do: {1, 3, 6, 1, 5, 5, 7, 3, 28}
def oid(:"id-kp-cmcArchive"), do: {1, 3, 6, 1, 5, 5, 7, 3, 29}
def oid(:"id-kp-bgpsec-router"), do: {1, 3, 6, 1, 5, 5, 7, 3, 30}
def oid(:"id-kp-BrandIndicatorforMessageIdentification"), do: {1, 3, 6, 1, 5, 5, 7, 3, 31}
def oid(:"id-kp-cmKGA"), do: {1, 3, 6, 1, 5, 5, 7, 3, 32}
def oid(:"id-kp-rpcTLSClient"), do: {1, 3, 6, 1, 5, 5, 7, 3, 33}
def oid(:"id-kp-rpcTLSServer"), do: {1, 3, 6, 1, 5, 5, 7, 3, 34}
def oid(:"id-kp-bundleSecurity"), do: {1, 3, 6, 1, 5, 5, 7, 3, 35}
def oid(:"id-kp-documentSigning"), do: {1, 3, 6, 1, 5, 5, 7, 3, 36}
def oid(:"id-kp-jwt"), do: {1, 3, 6, 1, 5, 5, 7, 3, 37}
def oid(:"id-kp-httpContentEncrypt"), do: {1, 3, 6, 1, 5, 5, 7, 3, 38}
def oid(:"id-kp-oauthAccessTokenSigning"), do: {1, 3, 6, 1, 5, 5, 7, 3, 39}
end
[1]. Cisco. PKI: Simplify Certificate Provisioning with EST. 2016
[2]. SYNRC CA/EST Server in Elixir (DHARMA)
[3]. Clarification of RFC7030 CSR Attributes definition
[4]. RFC 7030
[5]. Foundries.io EST Server in Go (BSD-3)