Rumah >pembangunan bahagian belakang >Golang >Apabila menandatangani sijil, pengecam kunci kebenaran disalin ke SKID
editor php Strawberry menegaskan semasa memperkenalkan sijil menandatangani bahawa pengecam kunci yang dibenarkan (SKID) memainkan peranan penting dalam proses menandatangani. Apabila sijil ditandatangani, SKID disalin ke dalam sijil dan mengenal pasti kunci dibenarkan sijil. Kewujudan pengecam ini dapat membantu memastikan ketulenan dan kesahihan sijil, dan juga memudahkan pengesahan dan pengurusan sijil seterusnya. Menyalin SKID ialah langkah yang perlu semasa menandatangani sijil, dan ia memainkan peranan penting dalam penggunaan dan penyelenggaraan sijil.
Saya cuba tandatangan sijil menggunakan csr dan spacemonkeygo/openssl
wrapper.
Perintah openssl konsol untuk menandatangani sijil berfungsi seperti yang diharapkan dan saya mendapat sijil yang sah.
openssl x509 -req -days 365 -in cert_client.csr -ca ca/root.crt -cakey ca/root.key -set_serial 10101 -out cert_client.crt -extfile ca/extensions.cnf
Seperti yang dapat dilihat daripada tangkapan skrin, keyid skid dan issuer adalah berbeza.
Walau bagaimanapun, kod saya dalam go memberikan sijil yang salah, di mana skid mengandungi nilai tepat keyid yang mengeluarkan sijil. Ini menyebabkan nilai tidak sah untuk "Pengeluar" disalin dalam "Pengecam Kunci Kuasa": memandangkan skid adalah sama dengan keyid pengeluar, ia "berfikir" sijil dikeluarkan sendiri.
package main import ( "github.com/spacemonkeygo/openssl" "math/big" "os" "time" ) func main() { crtfilepath := filepath("ca/root.crt") keyfilepath := filepath("ca/root.key") certca, privatekeyca, err := getrootca(pathcert(crtfilepath), pathkey(keyfilepath)) if err != nil { panic(err) } serialnumber := big.newint(10101) country := "ru" organization := "some organization" commonname := "commonname" expirationdate := time.now().adddate(1, 0, 0) certinfo := &openssl.certificateinfo{ serial: serialnumber, expires: expirationdate.sub(time.now()), commonname: commonname, // will fail if these are empty or not initialized country: country, organization: organization, } // just for example. publickey is received from csr privatekeycert, err := openssl.generatersakey(2048) if err != nil { panic(err) } newcert, err := openssl.newcertificate(certinfo, openssl.publickey(privatekeycert)) if err != nil { panic(err) } err = newcert.setversion(openssl.x509_v3) if err != nil { panic(err) } // (?) must be called before adding extensions err = newcert.setissuer(certca) if err != nil { panic(err) } err = newcert.addextension(openssl.nid_basic_constraints, "critical,ca:false") if err != nil { panic(err) } err = newcert.addextension(openssl.nid_subject_key_identifier, "hash") if err != nil { panic(err) } err = newcert.addextension(openssl.nid_authority_key_identifier, "keyid:always,issuer:always") if err != nil { panic(err) } err = newcert.sign(privatekeyca, openssl.evp_sha256) if err != nil { panic(err) } pembytes, err := newcert.marshalpem() if err != nil { panic(err) } err = os.writefile("generated.crt", pembytes, os.filemode(0644)) if err != nil { panic(err) } print("done") } type filepath string type pathcert string type pathkey string func getrootca(pathcert pathcert, pathkey pathkey) (*openssl.certificate, openssl.privatekey, error) { capublickeyfile, err := os.readfile(string(pathcert)) if err != nil { return nil, nil, err } certca, err := openssl.loadcertificatefrompem(capublickeyfile) if err != nil { return nil, nil, err } caprivatekeyfile, err := os.readfile(string(pathkey)) if err != nil { return nil, nil, err } privatekeyca, err := openssl.loadprivatekeyfrompem(caprivatekeyfile) if err != nil { return nil, nil, err } return certca, privatekeyca, nil }
(Yang dijana betul)
Jika saya tidak memanggil setissuer
, skid baru dijana, tetapi sijil yang dijana masih menunjukkan "tidak sah".
Apakah yang saya lakukan salah dalam kod saya?
Kemas kini:
Saya membandingkan pelaksanaan menambah sambungan untuk 2 pembungkus: spacemonkey/go
和 pyopenssl
.
Pergi ke:
// add an extension to a certificate. // extension constants are nid_* as found in openssl. func (c *certificate) addextension(nid nid, value string) error { issuer := c if c.issuer != nil { issuer = c.issuer } var ctx c.x509v3_ctx c.x509v3_set_ctx(&ctx, c.x, issuer.x, nil, nil, 0) ex := c.x509v3_ext_conf_nid(nil, &ctx, c.int(nid), c.cstring(value)) if ex == nil { return errors.new("failed to create x509v3 extension") } defer c.x509_extension_free(ex) if c.x509_add_ext(c.x, ex, -1) <= 0 { return errors.new("failed to add x509v3 extension") } return nil }
python (beberapa komen diketepikan):
# X509Extension::__init__ def __init__( self, type_name: bytes, critical: bool, value: bytes, subject: Optional["X509"] = None, issuer: Optional["X509"] = None, ) -> None: ctx = _ffi.new("X509V3_CTX*") # A context is necessary for any extension which uses the r2i # conversion method. That is, X509V3_EXT_nconf may segfault if passed # a NULL ctx. Start off by initializing most of the fields to NULL. _lib.X509V3_set_ctx(ctx, _ffi.NULL, _ffi.NULL, _ffi.NULL, _ffi.NULL, 0) # We have no configuration database - but perhaps we should (some # extensions may require it). _lib.X509V3_set_ctx_nodb(ctx) # Initialize the subject and issuer, if appropriate. ctx is a local, # and as far as I can tell none of the X509V3_* APIs invoked here steal # any references, so no need to mess with reference counts or # duplicates. if issuer is not None: if not isinstance(issuer, X509): raise TypeError("issuer must be an X509 instance") ctx.issuer_cert = issuer._x509 if subject is not None: if not isinstance(subject, X509): raise TypeError("subject must be an X509 instance") ctx.subject_cert = subject._x509 if critical: # There are other OpenSSL APIs which would let us pass in critical # separately, but they're harder to use, and since value is already # a pile of crappy junk smuggling a ton of utterly important # structured data, what's the point of trying to avoid nasty stuff # with strings? (However, X509V3_EXT_i2d in particular seems like # it would be a better API to invoke. I do not know where to get # the ext_struc it desires for its last parameter, though.) value = b"critical," + value extension = _lib.X509V3_EXT_nconf(_ffi.NULL, ctx, type_name, value) if extension == _ffi.NULL: _raise_current_error() self._extension = _ffi.gc(extension, _lib.X509_EXTENSION_free)
Perbezaan yang jelas ialah versi api: python menerima subject
和 issuer
sebagai parameter untuk lebihan muatan. Versi pergi tidak.
Perbezaan pelaksanaan adalah seperti berikut:
x509v3_ext_nconf
x509v3_ext_conf_nid
Dipanggil masuk pergi
Kedua-dua fungsi boleh didapati di github. Saya rasa tidak mungkin untuk menambah sambungan skid apabila menggunakan openspacemonkey/go-openssl dengan tandatangan ca.
Nampaknya satu-satunya cara ialah menggunakan pengikatan c secara manual dan "lakukan seperti python".
Saya melaksanakan penyelesaian yang bijak untuk menambah skid dan autoritikeyidentifier. Sijil yang dijana adalah sah. Walau bagaimanapun, memandangkan ahli certificate
结构体的 x *c.x509
tidak dieksport, satu-satunya cara untuk mengaksesnya adalah melalui petunjuk dan hantaran yang tidak selamat.
Ini bukan pendekatan yang disyorkan, tetapi cara untuk melakukannya sehingga kemas kini spacemonkey/go
(yang saya ragu akan berlaku dalam masa terdekat).
func addAuthorityKeyIdentifier(c *openssl.Certificate) error { var ctx C.X509V3_CTX C.X509V3_set_ctx(&ctx, nil, nil, nil, nil, 0) // this is ugly and very unsafe! cx509 := *(**C.X509)(unsafe.Pointer(c)) cx509Issuer := cx509 if c.Issuer != nil { cx509Issuer = *(**C.X509)(unsafe.Pointer(c.Issuer)) } ctx.issuer_cert = cx509Issuer cExtName := C.CString("authorityKeyIdentifier") defer C.free(unsafe.Pointer(cExtName)) cExtValue := C.CString("keyid:always,issuer:always") defer C.free(unsafe.Pointer(cExtValue)) extension := C.X509V3_EXT_nconf(nil, &ctx, cExtName, cExtValue) if extension == nil { return errors.New("failed to set 'authorityKeyIdentifier' extension") } defer C.X509_EXTENSION_free(extension) addResult := C.X509_add_ext(cx509, extension, -1) if addResult == 0 { return errors.New("failed to set 'authorityKeyIdentifier' extension") } return nil } func addSKIDExtension(c *openssl.Certificate) error { var ctx C.X509V3_CTX C.X509V3_set_ctx(&ctx, nil, nil, nil, nil, 0) // this is ugly and very unsafe! cx509 := *(**C.X509)(unsafe.Pointer(c)) _ = cx509 ctx.subject_cert = cx509 _ = ctx cExtName := C.CString("subjectKeyIdentifier") defer C.free(unsafe.Pointer(cExtName)) cExtValue := C.CString("hash") defer C.free(unsafe.Pointer(cExtValue)) extension := C.X509V3_EXT_nconf(nil, &ctx, cExtName, cExtValue) if extension == nil { return errors.New("failed to set 'subjectKeyIdentifier' extension") } defer C.X509_EXTENSION_free(extension) // adding itself as a subject addResult := C.X509_add_ext(cx509, extension, -1) if addResult == 0 { return errors.New("failed to set 'subjectKeyIdentifier' extension") } return nil }
Atas ialah kandungan terperinci Apabila menandatangani sijil, pengecam kunci kebenaran disalin ke SKID. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!