Erlang 21 - 3. Getting Started

3 शुरू हो रहा है




erlang

3 शुरू हो रहा है

यह अनुभाग सार्वजनिक कुंजी API का उपयोग करने के तरीके का वर्णन करता है। निम्नलिखित अनुभागों में उपयोग की जाने वाली कुंजी और प्रमाण पत्र केवल सार्वजनिक कुंजी अनुप्रयोग के परीक्षण के लिए उत्पन्न होते हैं।

निम्नलिखित उदाहरणों में कुछ शेल प्रिंटआउट को पठनीयता के लिए संक्षिप्त किया जाता है।

3.1 पीईएम फाइलें

सार्वजनिक-कुंजी डेटा (कुंजी, प्रमाण पत्र, और इसी तरह) को गोपनीयता बढ़ाया मेल (पीईएम) प्रारूप में संग्रहीत किया जा सकता है। PEM फ़ाइलों में निम्न संरचना होती है:

<text>
-----BEGIN <SOMETHING>-----
<Attribute> : <Value>
<Base64 encoded DER data>
-----END <SOMETHING>-----
<text>

एक फ़ाइल में कई BEGIN/END ब्लॉक हो सकते हैं। ब्लॉक के बीच पाठ लाइनों को नजरअंदाज कर दिया जाता है। गुण, यदि मौजूद हैं, तो Proc-Type और DEK-Info को छोड़कर अनदेखा कर दिया जाता है, जिसका उपयोग DER डेटा एन्क्रिप्ट होने पर किया जाता है।

डीएसए प्राइवेट की

एक डीएसए निजी कुंजी इस प्रकार दिख सकती है:

ध्यान दें

सार्वजनिक कुंजी अनुप्रयोग द्वारा फ़ाइल हैंडलिंग नहीं की जाती है।

1> {ok, PemBin} = file:read_file("dsa.pem").
{ok,<<"-----BEGIN DSA PRIVATE KEY-----\nMIIBuw"...>>}

निम्नलिखित PEM फ़ाइल में केवल एक प्रविष्टि है, एक निजी DSA कुंजी:

2> [DSAEntry] =  public_key:pem_decode(PemBin).
[{'DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,
                    179,230,217,37,99,144,157,21,228,204,
		    162,207,61,246,...>>,
		    not_encrypted}]
3> Key = public_key:pem_entry_decode(DSAEntry).
#'DSAPrivateKey'{version = 0,
                 p = 12900045185019966618...6593,
                 q = 1216700114794736143432235288305776850295620488937,
                 g = 10442040227452349332...47213,
                 y = 87256807980030509074...403143,
                 x = 510968529856012146351317363807366575075645839654}

RSA पासवर्ड के साथ निजी कुंजी

पासवर्ड के साथ एन्क्रिप्ट किया गया एक RSA निजी कुंजी निम्न प्रकार से देख सकता है:

1> {ok, PemBin} = file:read_file("rsa.pem").
{ok,<<"Bag Attribut"...>>}

निम्नलिखित PEM फ़ाइल में केवल एक प्रविष्टि है, एक निजी RSA कुंजी:

2>[RSAEntry] = public_key:pem_decode(PemBin).
[{'RSAPrivateKey',<<224,108,117,203,152,40,15,77,128,126,
                    221,195,154,249,85,208,202,251,109,
                    119,120,57,29,89,19,9,...>>,
                  {"DES-EDE3-CBC",<<"kÙeø¼pµL">>}}]

इस उदाहरण में, पासवर्ड "abcd1234" :

3> Key = public_key:pem_entry_decode(RSAEntry, "abcd1234").
    #'RSAPrivateKey'{version = 'two-prime',
                 modulus = 1112355156729921663373...2737107,
                 publicExponent = 65537,
                 privateExponent = 58064406231183...2239766033,
                 prime1 = 11034766614656598484098...7326883017,
                 prime2 = 10080459293561036618240...77738643771,
                 exponent1 = 77928819327425934607...22152984217,
                 exponent2 = 36287623121853605733...20588523793,
                 coefficient = 924840412626098444...41820968343,
                 otherPrimeInfos = asn1_NOVALUE}

X509 प्रमाण पत्र

निम्नलिखित X509 प्रमाणपत्र का एक उदाहरण है:

1> {ok, PemBin} = file:read_file("cacerts.pem").
{ok,<<"-----BEGIN CERTIFICATE-----\nMIIC7jCCAl"...>>}

निम्न फ़ाइल में दो प्रमाणपत्र शामिल हैं:

2> [CertEntry1, CertEntry2] = public_key:pem_decode(PemBin).
[{'Certificate',<<48,130,2,238,48,130,2,87,160,3,2,1,2,2,
                  9,0,230,145,97,214,191,2,120,150,48,13,
                  ...>>,
                not_encrypted},
 {'Certificate',<<48,130,3,200,48,130,3,49,160,3,2,1,2,2,1,
                  1,48,13,6,9,42,134,72,134,247,...>>,
                not_encrypted}]

प्रमाणपत्र हमेशा की तरह डिकोड किए जा सकते हैं:

2> Cert = public_key:pem_entry_decode(CertEntry1).
#'Certificate'{
    tbsCertificate =
        #'TBSCertificate'{
            version = v3,serialNumber = 16614168075301976214,
            signature =
                #'AlgorithmIdentifier'{
                    algorithm = {1,2,840,113549,1,1,5},
                    parameters = <<5,0>>},
            issuer =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = <<19,8,101,114,108,97,110,103,67,65>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = <<19,10,69,114,108,97,110,103,32,79,84,80>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = <<19,11,69,114,105,99,115,115,111,110,32,65,66>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = <<19,9,83,116,111,99,107,104,111,108,109>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,6},
                          value = <<19,2,83,69>>}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = <<22,22,112,101,116,101,114,64,101,114,...>>}]]},
            validity =
                #'Validity'{
                    notBefore = {utcTime,"080109082929Z"},
                    notAfter = {utcTime,"080208082929Z"}},
            subject =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = <<19,8,101,114,108,97,110,103,67,65>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = <<19,10,69,114,108,97,110,103,32,79,84,80>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = <<19,11,69,114,105,99,115,115,111,110,32,...>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = <<19,9,83,116,111,99,107,104,111,108,...>>}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,6},
                          value = <<19,2,83,69>>}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = <<22,22,112,101,116,101,114,64,...>>}]]},
            subjectPublicKeyInfo =
                #'SubjectPublicKeyInfo'{
                    algorithm =
                        #'AlgorithmIdentifier'{
                            algorithm = {1,2,840,113549,1,1,1},
                            parameters = <<5,0>>},
                    subjectPublicKey =
                        {0,<<48,129,137,2,129,129,0,203,209,187,77,73,231,90,...>>}},
            issuerUniqueID = asn1_NOVALUE,
            subjectUniqueID = asn1_NOVALUE,
            extensions =
                [#'Extension'{
                     extnID = {2,5,29,19},
                     critical = true,
                     extnValue = [48,3,1,1,255]},
                 #'Extension'{
                     extnID = {2,5,29,15},
                     critical = false,
                     extnValue = [3,2,1,6]},
                 #'Extension'{
                     extnID = {2,5,29,14},
                     critical = false,
                     extnValue = [4,20,27,217,65,152,6,30,142|...]},
                 #'Extension'{
                     extnID = {2,5,29,17},
                     critical = false,
                     extnValue = [48,24,129,22,112,101,116,101|...]}]},
    signatureAlgorithm =
        #'AlgorithmIdentifier'{
            algorithm = {1,2,840,113549,1,1,5},
            parameters = <<5,0>>},
    signature =
    <<163,186,7,163,216,152,63,47,154,234,139,73,154,96,120,
    165,2,52,196,195,109,167,192,...>>}

प्रमाणपत्र के कुछ हिस्सों को public_key:der_decode/2 , उस भाग के ASN.1 प्रकार का उपयोग करके डीकोड किया जा सकता है। हालाँकि, एप्लिकेशन-विशिष्ट प्रमाणपत्र एक्सटेंशन के लिए एप्लिकेशन-विशिष्ट ASN.1 डिकोड / एन्कोड-फ़ंक्शन की आवश्यकता होती है। हाल के उदाहरण में, rdnSequence का पहला मूल्य ASN.1 प्रकार 'X520CommonName'. ({2,5,4,3} = ?id-at-commonName) 'X520CommonName'. ({2,5,4,3} = ?id-at-commonName) :

public_key:der_decode('X520CommonName', <<19,8,101,114,108,97,110,103,67,65>>).
{printableString,"erlangCA"}

हालाँकि, प्रमाणपत्रों को pkix_decode_cert/2 का उपयोग करके भी डिकोड किया जा सकता है, जो किसी प्रमाणपत्र के मानक भागों को कस्टमाइज़ और पुन: pkix_decode_cert/2 कर सकता है:

3>{_, DerCert, _} = CertEntry1.
4> public_key:pkix_decode_cert(DerCert, otp).
#'OTPCertificate'{
    tbsCertificate =
        #'OTPTBSCertificate'{
            version = v3,serialNumber = 16614168075301976214,
            signature =
                #'SignatureAlgorithm'{
                    algorithm = {1,2,840,113549,1,1,5},
                    parameters = 'NULL'},
            issuer =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = {printableString,"erlangCA"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = {printableString,"Erlang OTP"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = {printableString,"Ericsson AB"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = {printableString,"Stockholm"}}],
                     [#'AttributeTypeAndValue'{type = {2,5,4,6},value = "SE"}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = "[email protected]"}]]},
            validity =
                #'Validity'{
                    notBefore = {utcTime,"080109082929Z"},
                    notAfter = {utcTime,"080208082929Z"}},
            subject =
                {rdnSequence,
                    [[#'AttributeTypeAndValue'{
                          type = {2,5,4,3},
                          value = {printableString,"erlangCA"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,11},
                          value = {printableString,"Erlang OTP"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,10},
                          value = {printableString,"Ericsson AB"}}],
                     [#'AttributeTypeAndValue'{
                          type = {2,5,4,7},
                          value = {printableString,"Stockholm"}}],
                     [#'AttributeTypeAndValue'{type = {2,5,4,6},value = "SE"}],
                     [#'AttributeTypeAndValue'{
                          type = {1,2,840,113549,1,9,1},
                          value = "[email protected]"}]]},
            subjectPublicKeyInfo =
                #'OTPSubjectPublicKeyInfo'{
                    algorithm =
                        #'PublicKeyAlgorithm'{
                            algorithm = {1,2,840,113549,1,1,1},
                            parameters = 'NULL'},
                    subjectPublicKey =
                        #'RSAPublicKey'{
                            modulus =
                                1431267547247997...37419,
                            publicExponent = 65537}},
            issuerUniqueID = asn1_NOVALUE,
            subjectUniqueID = asn1_NOVALUE,
            extensions =
                [#'Extension'{
                     extnID = {2,5,29,19},
                     critical = true,
                     extnValue =
                         #'BasicConstraints'{
                             cA = true,pathLenConstraint = asn1_NOVALUE}},
                 #'Extension'{
                     extnID = {2,5,29,15},
                     critical = false,
                     extnValue = [keyCertSign,cRLSign]},
                 #'Extension'{
                     extnID = {2,5,29,14},
                     critical = false,
                     extnValue = [27,217,65,152,6,30,142,132,245|...]},
                 #'Extension'{
                     extnID = {2,5,29,17},
                     critical = false,
                     extnValue = [{rfc822Name,"[email protected]"}]}]},
    signatureAlgorithm =
        #'SignatureAlgorithm'{
            algorithm = {1,2,840,113549,1,1,5},
            parameters = 'NULL'},
    signature =
         <<163,186,7,163,216,152,63,47,154,234,139,73,154,96,120,
           165,2,52,196,195,109,167,192,...>>}

यह कॉल public_key:pem_entry_decode(CertEntry1) बराबर है public_key:pem_entry_decode(CertEntry1) :

5> public_key:pkix_decode_cert(DerCert, plain).
#'Certificate'{ ...}

PEM प्रारूप करने के लिए सार्वजनिक कुंजी डेटा एन्कोडिंग

यदि आपके पास सार्वजनिक-कुंजी डेटा है और PEM फ़ाइल बनाना चाहते हैं, तो इसे फ़ंक्शन public_key:pem_entry_encode/2 और pem_encode/1 कहकर किया जा सकता है और परिणाम को फ़ाइल में सहेजा जा सकता है। उदाहरण के लिए, मान लें कि आपके पास PubKey = 'RSAPublicKey'{} । फिर आप PEM- "RSA PUBLIC KEY" फ़ाइल (ASN.1 प्रकार 'RSAPublicKey' ) या PEM- "सार्वजनिक कुंजी" फ़ाइल ( 'SubjectPublicKeyInfo' प्रकार) बना सकते हैं।

PEM-entry का दूसरा तत्व ASN.1 DER एन्कोडेड कुंजी डेटा है:

1> PemEntry = public_key:pem_entry_encode('RSAPublicKey', RSAPubKey).
{'RSAPublicKey', <<48,72,...>>, not_encrypted}

2> PemBin = public_key:pem_encode([PemEntry]).
<<"-----BEGIN RSA PUBLIC KEY-----\nMEgC...>>

3> file:write_file("rsa_pub_key.pem", PemBin).
ok

या:

1> PemEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey).
{'SubjectPublicKeyInfo', <<48,92...>>, not_encrypted}

2> PemBin = public_key:pem_encode([PemEntry]).
<<"-----BEGIN PUBLIC KEY-----\nMFw...>>

3> file:write_file("pub_key.pem", PemBin).
ok

3.2 आरएसए सार्वजनिक कुंजी क्रिप्टोग्राफी

मान लीजिए कि आपके पास निम्नलिखित निजी कुंजी और एक सार्वजनिक कुंजी है:

  • PrivateKey = #'RSAPrivateKey{}' और सादा Msg = binary()
  • PublicKey = #'RSAPublicKey'{}

तो आप निम्नानुसार आगे बढ़ सकते हैं:

निजी कुंजी के साथ एन्क्रिप्ट करें:

RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey),
Msg = public_key:decrypt_public(RsaEncrypted, PublicKey),

सार्वजनिक कुंजी के साथ एन्क्रिप्ट करें:

RsaEncrypted = public_key:encrypt_public(Msg, PublicKey),
Msg = public_key:decrypt_private(RsaEncrypted, PrivateKey),
ध्यान दें

आप आम तौर पर केवल एक एन्क्रिप्ट या डिक्रिप्ट ऑपरेशंस में से एक करते हैं, और पीयर दूसरे को करता है। यह सामान्य रूप से एक आदिम डिजिटल हस्ताक्षर के रूप में विरासत अनुप्रयोगों में उपयोग किया जाता है।

३.३ डिजिटल हस्ताक्षर

मान लीजिए कि आपके पास निम्नलिखित निजी कुंजी और एक सार्वजनिक कुंजी है:

  • PrivateKey = #'RSAPrivateKey{}' या #'DSAPrivateKey'{} और सादा Msg = binary()
  • PublicKey = #'RSAPublicKey'{} या {integer(), #'DssParams'{}}

तो आप निम्नानुसार आगे बढ़ सकते हैं:

Signature = public_key:sign(Msg, sha, PrivateKey),
true = public_key:verify(Msg, sha, Signature, PublicKey),
ध्यान दें

आप आम तौर पर केवल एक साइन या ऑपरेशन को सत्यापित करते हैं, और पीयर दूसरे को करता है।

sign या verify कॉल sign से पहले संदेश को पचाने की गणना करना उचित हो सकता है, और फिर दूसरे तर्क के रूप में none का none उपयोग none करें:

Digest = crypto:sha(Msg),
Signature = public_key:sign(Digest, none, PrivateKey),
true = public_key:verify(Digest, none, Signature, PublicKey),

3.4 प्रमाणपत्र होस्टनाम सत्यापित करना

पृष्ठभूमि

जब कोई क्लाइंट एक सर्वर प्रमाणपत्र की जाँच करता है, तो कई जाँचें उपलब्ध होती हैं जैसे जाँच कि प्रमाणपत्र निरस्त नहीं है, जाली नहीं है या पुराना नहीं है।

हालाँकि, ऐसे हमले हैं जो उन जाँचों द्वारा नहीं किए गए हैं। मान लीजिए कि एक बुरे आदमी ने डीएनएस संक्रमण से दम तोड़ दिया है। तब ग्राहक विश्वास कर सकता था कि यह एक मेजबान से जुड़ रहा है, लेकिन दूसरे पर बुरा है। हालांकि यह बुराई है, यह एक पूरी तरह से कानूनी प्रमाण पत्र हो सकता है! प्रमाण पत्र में एक वैध हस्ताक्षर है, इसे निरस्त नहीं किया गया है, प्रमाण पत्र श्रृंखला नकली नहीं है और एक विश्वसनीय जड़ और इसी तरह है।

यह पता लगाने के लिए कि सर्वर अभीष्ट नहीं है, क्लाइंट को होस्टनाम सत्यापन अतिरिक्त रूप से करना चाहिए। यह प्रक्रिया RFC 6125 में वर्णित है। विचार यह है कि प्रमाणपत्र उन होस्टनामों को सूचीबद्ध करता है जिनसे इसे प्राप्त किया जा सकता है। यह प्रमाण पत्र जारीकर्ता द्वारा जाँच की जाती है जब प्रमाणपत्र पर हस्ताक्षर किए जाते हैं। इसलिए यदि प्रमाण-पत्र किसी विश्वसनीय रूट द्वारा जारी किया जाता है तो ग्राहक उस पर हस्ताक्षर किए गए मेजबान नामों पर भरोसा कर सकता है।

RFC 6125, section 6 साथ-साथ RFC 6125 appendix B में परिभाषित प्रोटोकॉल आश्रित भिन्नताओं के लिए एक डिफ़ॉल्ट होस्टनाम मिलान प्रक्रिया निर्धारित है। डिफ़ॉल्ट प्रक्रिया public_key:pkix_verify_hostname/2,3 में कार्यान्वित की public_key:pkix_verify_hostname/2,3 । क्लाइंट के लिए विकल्प सूची का उपयोग करके संशोधित नियमों में हुक करना संभव है।

कुछ शब्दावली की आवश्यकता है: प्रमाणपत्र होस्टनाम (ओं) को प्रस्तुत करता है जिस पर यह मान्य है। जिन्हें प्रस्तुत आईडी कहा जाता है। होस्टनाम (ओं) को जो ग्राहक इसे जोड़ता है, उसे संदर्भ आईडी कहा जाता है। मिलान नियमों का उद्देश्य यह सत्यापित करना है कि प्रस्तुत आईडी में से कम से कम एक संदर्भ आईडी से मेल खाती है। यदि नहीं, तो सत्यापन विफल हो जाता है।

आईडी में सामान्य पूरी तरह से योग्य डोमेन नाम होते हैं, जैसे foo.example.com , लेकिन आईपी पते की सिफारिश नहीं की जाती है। आरएफसी का वर्णन है कि यह संदर्भ आईडी को कैसे प्राप्त करने के बारे में सुरक्षा कारणों के साथ-साथ अनुशंसित नहीं है।

अंतर्राष्ट्रीय डोमेन नाम समर्थित नहीं हैं।

सत्यापन की प्रक्रिया

परंपरागत रूप से प्रस्तुत आईडी को CN नाम के रूप में Subject प्रमाणपत्र फ़ील्ड में पाया गया था। यह अभी भी काफी सामान्य है। एक प्रमाण पत्र को प्रिंट करते समय वे इस प्रकार दिखाते हैं:

$ openssl x509 -text < cert.pem
...
Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
...

उदाहरण Subject फ़ील्ड में एक C, दो CN और एक O भाग है। यह केवल CN (सामान्य नाम) है जिसका उपयोग hostname सत्यापन द्वारा किया जाता है। दो अन्य (C और O) का उपयोग यहाँ तब भी नहीं किया जाता है जब उनमें O भाग जैसा डोमेन नाम होता है। C और O भागों को कहीं और परिभाषित किया गया है और केवल अन्य कार्यों के लिए सार्थक है।

उदाहरण में प्रस्तुत ID उदाहरण example.com साथ-साथ *.example.com मेल खाते हैं। उदाहरण के लिए foo.example.com और bar.example.com दोनों मेल खाते हैं लेकिन foo.bar.example.com नहीं। नाम erlang.org मेल खाता है क्योंकि यह CN नहीं है।

ऐसे मामले में जहां प्रस्तुत आईडी को Subject प्रमाणपत्र क्षेत्र से प्राप्त किया जाता है, नामों में वाइल्डकार्ड वर्ण हो सकते हैं। फ़ंक्शन इसे chapter 6.4.3 in RFC 6125 परिभाषित किया गया है।

केवल एक वाइल्डकार्ड वर्ण हो सकता है और वह पहले लेबल में है, उदाहरण के लिए: *.example.com । यह foo.example.com मेल खाता है, लेकिन न तो example.com और न ही foo.bar.example.com

वाइल्डकार्ड के पहले या बाद में लेबल वर्ण हो सकते हैं। उदाहरण के लिए: a*d.example.com abcd.example.com और ad.example.com मेल खाता है, लेकिन ab.cd.example.com नहीं।

पिछले उदाहरण में कोई संकेत नहीं है कि कौन से प्रोटोकॉल अपेक्षित हैं। तो एक क्लाइंट को इस बात का कोई संकेत नहीं है कि यह एक वेब सर्वर, एक ldap सर्वर या शायद एक sip सर्वर है जो इससे जुड़ा हुआ है। प्रमाण पत्र में फ़ील्ड हैं जो यह इंगित कर सकते हैं। अधिक सटीक होने के लिए, rfc X509v3 extensions फ़ील्ड में X509v3 Subject Alternative Name के उपयोग का परिचय देता है:

$ openssl x509 -text < cert.pem
...
X509v3 extensions:
    X509v3 Subject Alternative Name:
        DNS:kb.example.org, URI:https://www.example.org
...

यहाँ kb.example.org किसी भी प्रोटोकॉल का काम करता है जबकि www.example.org एक सुरक्षित वेब सर्वर प्रस्तुत करता है।

अगले उदाहरण में Subject और Subject Alternate Name दोनों मौजूद हैं:

$ openssl x509 -text < cert.pem
...
Subject: C=SE, CN=example.com, CN=*.example.com, O=erlang.org
...
X509v3 extensions:
    X509v3 Subject Alternative Name:
        DNS:kb.example.org, URI:https://www.example.org
...

RFC कहता है कि यदि कोई प्रमाणपत्र संदर्भ आईडी को एक Subject Alternate Name फ़ील्ड में परिभाषित करता है, तो Subject फ़ील्ड को होस्ट नाम जाँच के लिए उपयोग नहीं किया जाना चाहिए, भले ही उसमें मान्य CN नाम हों। इसलिए केवल kb.example.org और https://www.example.org मैच करता है। यह example.com और foo.example.com दोनों के लिए विफल रहता है क्योंकि वे Subject फ़ील्ड में हैं, जिन्हें चेक नहीं किया गया है क्योंकि Subject Alternate Name फ़ील्ड मौजूद है।

फ़ंक्शन कॉल उदाहरण

ध्यान दें

अन्य एप्लिकेशन जैसे ssl / tls या https के पास विकल्प हो सकते हैं जो public_key:pkix_verify_hostname नीचे public_key:pkix_verify_hostname । आपको शायद इसे सीधे कॉल नहीं करना होगा

मान लीजिए कि हमारा ग्राहक वेब सर्वर https://www.example.net से जुड़ने की अपेक्षा करता है। यह URI क्लाइंट का संदर्भ आईडी है। कॉल होगा:

public_key:pkix_verify_hostname(CertFromHost,
                                [{uri_id, "https://www.example.net"}
                                ]).

चेक के आधार पर कॉल true या false लौटेगी। कॉल करने वाले को आरएफसी में मिलान नियमों को संभालने की आवश्यकता नहीं है। मिलान आगे बढ़ेगा:

  • यदि कोई Subject Alternate Name फ़ील्ड है, तो फ़ंक्शन कॉल में {uniformResourceIdentifier,string()} की तुलना सर्टिफ़िकेट फ़ील्ड में किसी भी {uniformResourceIdentifier,string()} से की जाएगी। यदि दो strings() समान (केस असंवेदनशील) हैं, तो एक मैच है। सर्टिफ़िकेट फ़ील्ड में सभी {dNSName,string()} साथ तुलना में कॉल में {dns_id,string()} लिए भी यही लागू होता है।
  • यदि कोई Subject Alternate Name फ़ील्ड नहीं है, तो Subject फ़ील्ड की जाँच की जाएगी। सभी CN नामों की तुलना {uri_id,string()} और {dns_id,string()} से निकाले गए सभी होस्टनामों से की {uri_id,string()}

खोज तंत्र का विस्तार

कॉल करने वाला स्वयं निष्कर्षण और मिलान नियमों का उपयोग कर सकता है। यह दो विकल्पों fqdn_fun और match_fun साथ किया जाता है।

होस्टनाम निष्कर्षण

fqdn_fun uri_id या अन्य ReferenceID से होस्टनाम (पूरी तरह से योग्य डोमेन नाम) निकालता है जो public_key फ़ंक्शन में पूर्व-परिभाषित नहीं हैं। मान लीजिए कि आपके पास कुछ यूआरआई हैं, जिनमें एक बहुत ही विशेष प्रोटोकॉल-भाग: myspecial://example.com" । चूंकि यह एक गैर-मानक URI है, इसलिए Subject में CN-नाम मिलान के लिए कोई होस्टनाम नहीं निकाला जाएगा।

फ़ंक्शन को "सिखाना" कैसे निकालना है, आप एक मजेदार दे सकते हैं जो डिफ़ॉल्ट निष्कर्षण फ़ंक्शन को प्रतिस्थापित करता है। fqdn_fun एक तर्क लेता है और प्रत्येक CN-नाम या परमाणु default से मिलान होने के लिए एक string() या तो देता है जो डिफ़ॉल्ट fqdn निष्कर्षण फ़ंक्शन को आमंत्रित करेगा। undefined वापसी मान वर्तमान URI को fqdn निष्कर्षण से निकाल देता है।

...
Extract = fun({uri_id, "myspecial://"++HostName}) -> HostName;
             (_Else) -> default
          end,
...	 
public_key:pkix_verify_hostname(CertFromHost, RefIDs,
                                [{fqdn_fun, Extract}])
...
मैच ऑपरेशन को फिर से परिभाषित करना

डिफ़ॉल्ट मिलान हैंडल dns_id और uri_id को संभालता है। Uri_id में मान को Subject Alternate Name से मान के साथ समानता के लिए परीक्षण किया जाता है। यदि किसी अन्य प्रकार के मिलान की आवश्यकता है, तो match_fun विकल्प का उपयोग करें।

match_fun दो तर्क लेता है और या तो true , false या default रिटर्न default । मान default डिफ़ॉल्ट फ़ंक्शन फ़ंक्शन को आमंत्रित करेगा।

...
Match = fun({uri_id,"myspecial://"++A},
            {uniformResourceIdentifier,"myspecial://"++B}) ->
                                                   my_match(A,B);
           (_RefID, _PresentedID) ->
                               default
        end,
...
public_key:pkix_verify_hostname(CertFromHost, RefIDs,
                                [{match_fun, Match}]),
...

Subject फ़ील्ड के संदर्भ और CN मान के बीच मैच ऑपरेशन के मामले में, मज़े के लिए पहला तर्क ReferenceID से होस्टनाम निकाला जाता है, और दूसरा तर्क Subject से लिया गया tuple {cn, string()} है। खेत। यह Subject क्षेत्र से प्रस्तुत आईडी के लिए और Subject Alternate Name क्षेत्र से अलग मिलान नियम बनाना संभव बनाता है।

डिफॉल्ट मिलान तुलना करने से पहले स्ट्रिंग्स में एस्की मूल्यों को बदल देता है। match_fun को match_fun किसी भी match_fun बिना कहा जाता है। इसका कारण उपयोगकर्ता को उन स्ट्रिंग्स का अप्रत्याशित संचालन करने में सक्षम करना है जहां मूल प्रारूप की आवश्यकता है।

एक सर्टिफिकेट "पिनिंग"

RFC 6125 पिनिंग को परिभाषित करता है:

"अनुप्रयोग सेवा के प्रमाणपत्र और क्लाइंट के संदर्भ पहचानकर्ताओं में से एक के बीच एक कैश्ड नाम एसोसिएशन स्थापित करने का कार्य, इस तथ्य के बावजूद कि प्रस्तुत पहचानकर्ताओं में से कोई भी दिए गए संदर्भ पहचानकर्ता से मेल नहीं खाता है ..."

उद्देश्य यह है कि मनुष्य के लिए एक तंत्र होना चाहिए अन्यथा एक दोषपूर्ण प्रमाण पत्र स्वीकार करना चाहिए। उदाहरण के लिए एक वेब ब्राउज़र में, आपको एक प्रश्न मिल सकता है

चेतावनी: आप साइट www.example.com पर जाना चाहते थे, लेकिन प्रमाणपत्र shop.example.com के लिए है। वैसे भी स्वीकार करो (हाँ / नहीं)?

यह विकल्प fail_callback साथ पूरा किया जा सकता है जिसे होस्टनाम सत्यापन विफल होने पर कहा जाएगा:

-include_lib("public_key/include/public_key.hrl"). % Record def
...
Fail = fun(#'OTPCertificate'{}=C) ->
             case in_my_cache(C) orelse my_accept(C) of
                 true ->
                      enter_my_cache(C),
                      true;
                 false ->
                      false
        end,
...
public_key:pkix_verify_hostname(CertFromHost, RefIDs,
                                [{fail_callback, Fail}]),
...

3.5 एसएसएच फाइलें

SSH आम तौर पर निजी कुंजी के लिए PEM फ़ाइलों का उपयोग करता है, लेकिन सार्वजनिक कुंजी संग्रहीत करने के लिए इसका अपना फ़ाइल स्वरूप होता है। public_key एप्लिकेशन का उपयोग SSH सार्वजनिक-कुंजी फ़ाइलों की सामग्री को पार्स करने के लिए किया जा सकता है।

RFC 4716 SSH सार्वजनिक कुंजी फ़ाइलें

RFC 4716 SSH फाइलें भ्रमवश PEM फ़ाइलों की तरह लगती हैं, लेकिन कुछ अंतर हैं:

1> {ok, SshBin} = file:read_file("ssh2_rsa_pub").
{ok, <<"---- BEGIN SSH2 PUBLIC KEY ----\nAAAA"...>>}

यह public_key:ssh_decode(SshBin, rfc4716_public_key) को कॉल करने के बराबर है:

2> public_key:ssh_decode(SshBin, public_key).
[{#'RSAPublicKey'{modulus = 794430685...91663,
                  publicExponent = 35}, []}]

ओपनएसएसएच सार्वजनिक कुंजी प्रारूप

OpenSSH सार्वजनिक कुंजी प्रारूप निम्नानुसार है:

1> {ok, SshBin} = file:read_file("openssh_dsa_pub").
{ok,<<"ssh-dss AAAAB3Nza"...>>}

यह public_key:ssh_decode(SshBin, openssh_public_key) को कॉल करने के बराबर है:

2>  public_key:ssh_decode(SshBin, public_key).
[{{15642692...694280725,
   #'Dss-Parms'{p = 17291273936...696123221,
                q = 1255626590179665817295475654204371833735706001853,
                g = 10454211196...480338645}},
  [{comment,"[email protected]"}]}]

ज्ञात मेजबान - ओपनएसएसएच प्रारूप

ज्ञात मेजबान - OpenSSH प्रारूप निम्नानुसार है:

1> {ok, SshBin} = file:read_file("known_hosts").
{ok,<<"hostname.domain.com,192.168.0.1 ssh-rsa AAAAB...>>}

सार्वजनिक कुंजी और उनसे संबंधित विशेषताओं की एक सूची देता है। कुंजी और विशेषता की प्रत्येक जोड़ी ज्ञात होस्ट फ़ाइल में एक प्रविष्टि से मेल खाती है:

2>  public_key:ssh_decode(SshBin, known_hosts).
[{#'RSAPublicKey'{modulus = 1498979460408...72721699,
                  publicExponent = 35},
  [{hostnames,["hostname.domain.com","192.168.0.1"]}]},
 {#'RSAPublicKey'{modulus = 14989794604088...2721699,
                  publicExponent = 35},
  [{comment,"[email protected]"},
   {hostnames,["|1|BWO5qDxk/cFH0wa05JLdHn+j6xQ=|rXQvIxh5cDD3C43k5DPDamawVNA="]}]}]

अधिकृत कुंजी - ओपनएसएसएच प्रारूप

अधिकृत कुंजी - OpenSSH प्रारूप इस प्रकार है:

1> {ok, SshBin} = file:read_file("auth_keys").
{ok, <<"command=\"dump /home\",no-pty,no-port-forwarding ssh-rsa AAA...>>}

सार्वजनिक कुंजी और उनसे संबंधित विशेषताओं की एक सूची देता है। कुंजी और विशेषता की प्रत्येक जोड़ी अधिकृत कुंजी फ़ाइल में एक प्रविष्टि से मेल खाती है:

2> public_key:ssh_decode(SshBin, auth_keys).
[{#'RSAPublicKey'{modulus = 794430685...691663,
                  publicExponent = 35},
  [{comment,"[email protected]"},
   {options,["command=\"dump/home\"","no-pty",
             "no-port-forwarding"]}]},
 {{1564269258491...607694280725,
   #'Dss-Parms'{p = 17291273936185...763696123221,
                q = 1255626590179665817295475654204371833735706001853,
                g = 10454211195705...60511039590076780999046480338645}},
  [{comment,"[email protected]"}]}]

सार्वजनिक कुंजी डेटा से एक SSH फ़ाइल बनाना

यदि आपको सार्वजनिक कुंजी PubKey और संबंधित विशेषताओं की एक सूची ssh_decode/2 , जैसा कि ssh_decode/2 द्वारा लौटाया गया है, तो आप उदाहरण के लिए एक नई SSH फ़ाइल बना सकते हैं:

N> SshBin = public_key:ssh_encode([{PubKey, Attributes}], openssh_public_key),
<<"ssh-rsa "...>>
N+1> file:write_file("id_rsa.pub", SshBin).
ok