From 0d764f5a3d12c6db4bcfe6c118bf20349be6c3e6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 3 Jul 2020 13:08:40 -0700 Subject: [PATCH] CGO glue for certificates, and Go formatting and other boring stuff. --- cmd/zerotier/cli/help.go | 2 +- core/Certificate.cpp | 34 +++--- core/Tests.cpp | 10 +- core/zerotier.h | 8 +- pkg/zerotier/address.go | 2 +- pkg/zerotier/api.go | 2 +- pkg/zerotier/certificate.go | 203 ++++++++++++++++++++++++++++++++ pkg/zerotier/endpoint.go | 2 +- pkg/zerotier/errors.go | 2 +- pkg/zerotier/fingerprint.go | 2 +- pkg/zerotier/identity.go | 2 +- pkg/zerotier/inetaddress.go | 2 +- pkg/zerotier/localconfig.go | 2 +- pkg/zerotier/locator.go | 2 +- pkg/zerotier/mac.go | 2 +- pkg/zerotier/misc.go | 26 +++- pkg/zerotier/multicastgroup.go | 2 +- pkg/zerotier/nativetap.go | 2 +- pkg/zerotier/network.go | 2 +- pkg/zerotier/node.go | 2 +- pkg/zerotier/osdep-posix.go | 2 +- pkg/zerotier/osdep-windows.go | 2 +- pkg/zerotier/path.go | 2 +- pkg/zerotier/peer.go | 2 +- pkg/zerotier/route.go | 2 +- pkg/zerotier/sizelimitwriter.go | 2 +- pkg/zerotier/tap.go | 2 +- 27 files changed, 276 insertions(+), 49 deletions(-) create mode 100644 pkg/zerotier/certificate.go diff --git a/cmd/zerotier/cli/help.go b/cmd/zerotier/cli/help.go index 38cbf6dfb..7c75802fe 100644 --- a/cmd/zerotier/cli/help.go +++ b/cmd/zerotier/cli/help.go @@ -81,7 +81,7 @@ Commands: verify Verify a signature certificate [args] - Certificate commands newid Create a new unique subject ID - newcsr Create a new CSR (signing request) + newcsr Create a new CSR (signing request) sign Sign a CSR to create a certificate verify Verify a certificate show List certificate for current node diff --git a/core/Certificate.cpp b/core/Certificate.cpp index 27648a449..83e1499e0 100644 --- a/core/Certificate.cpp +++ b/core/Certificate.cpp @@ -50,8 +50,8 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert) this->subject.networkCount = 0; this->subject.certificates = nullptr; this->subject.certificateCount = 0; - this->subject.updateUrls = nullptr; - this->subject.updateUrlCount = 0; + this->subject.updateURLs = nullptr; + this->subject.updateURLCount = 0; this->subject.uniqueId = nullptr; this->subject.uniqueIdProofSignature = nullptr; this->subject.uniqueIdSize = 0; @@ -80,10 +80,10 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert) addSubjectCertificate(cert.subject.certificates[i]); } - if (cert.subject.updateUrls) { - for (unsigned int i = 0; i < cert.subject.updateUrlCount; ++i) { - if (cert.subject.updateUrls[i]) - addSubjectUpdateUrl(cert.subject.updateUrls[i]); + if (cert.subject.updateURLs) { + for (unsigned int i = 0; i < cert.subject.updateURLCount; ++i) { + if (cert.subject.updateURLs[i]) + addSubjectUpdateUrl(cert.subject.updateURLs[i]); } } @@ -181,8 +181,8 @@ void Certificate::addSubjectUpdateUrl(const char *url) // Add pointer to local copy to pointer array and update C structure to point to // potentially reallocated array. m_updateUrls.push_back(m_strings.back().c_str()); - this->subject.updateUrls = m_updateUrls.data(); - this->subject.updateUrlCount = (unsigned int)m_updateUrls.size(); + this->subject.updateURLs = m_updateUrls.data(); + this->subject.updateURLCount = (unsigned int)m_updateUrls.size(); } void Certificate::setExtendedAttributes(const Dictionary &x) @@ -456,14 +456,14 @@ ZT_CertificateError Certificate::verify() const return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; } - if (this->subject.updateUrlCount) { - if (!this->subject.updateUrls) + if (this->subject.updateURLCount) { + if (!this->subject.updateURLs) return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; - for (unsigned int i = 0; i < this->subject.updateUrlCount; ++i) { - if (!this->subject.updateUrls[i]) + for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) { + if (!this->subject.updateURLs[i]) return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; } - } else if (this->subject.updateUrls) { + } else if (this->subject.updateURLs) { return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; } } catch (...) {} @@ -538,10 +538,10 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d d[Dictionary::arraySubscript(tmp, "s.c$", i)].assign(s.certificates[i], s.certificates[i] + ZT_SHA384_DIGEST_SIZE); } - d.add("s.u$", (uint64_t)s.updateUrlCount); - if (s.updateUrls) { - for (unsigned int i = 0; i < s.updateUrlCount; ++i) - d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateUrls[i]); + d.add("s.u$", (uint64_t)s.updateURLCount); + if (s.updateURLs) { + for (unsigned int i = 0; i < s.updateURLCount; ++i) + d.add(Dictionary::arraySubscript(tmp, "s.u$", i), s.updateURLs[i]); } if (s.name.country[0]) diff --git a/core/Tests.cpp b/core/Tests.cpp index c9c7b1608..0052fdd52 100644 --- a/core/Tests.cpp +++ b/core/Tests.cpp @@ -272,7 +272,7 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate (a.subject.timestamp != b.subject.timestamp) || (a.subject.identityCount != b.subject.identityCount) || (a.subject.networkCount != b.subject.networkCount) || - (a.subject.updateUrlCount != b.subject.updateUrlCount) || + (a.subject.updateURLCount != b.subject.updateURLCount) || (a.subject.uniqueIdSize != b.subject.uniqueIdSize) || (a.subject.uniqueIdProofSignatureSize != b.subject.uniqueIdProofSignatureSize) || (a.maxPathLength != b.maxPathLength) || @@ -324,12 +324,12 @@ static bool ZTT_deepCompareCertificates(const Certificate &a, const Certificate return false; } - for(unsigned int i=0;i 0 { + cc.internalSubjectIdentities = make([]C.ZT_Certificate_Identity, len(c.Subject.Identities)) + for i, id := range c.Subject.Identities { + if id.Identity == nil || !id.Identity.initCIdentityPtr() { + return nil + } + cc.internalSubjectIdentities[i].identity = id.Identity.cid + if id.Locator != nil { + cc.internalSubjectIdentities[i].locator = id.Locator.cl + } + } + cc.C.subject.identities = &cc.internalSubjectIdentities[0] + cc.C.subject.identityCount = C.uint(len(c.Subject.Identities)) + } + + if len(c.Subject.Networks) > 0 { + cc.internalSubjectNetworks = make([]C.ZT_Certificate_Network, len(c.Subject.Networks)) + for i, n := range c.Subject.Networks { + cc.internalSubjectNetworks[i].id = C.uint64_t(n.ID) + cc.internalSubjectNetworks[i].controller.address = C.uint64_t(n.Controller.Address) + if len(n.Controller.Hash) == 48 { + copy((*[48]byte)(unsafe.Pointer(&cc.internalSubjectNetworks[i].controller.hash[0]))[:], n.Controller.Hash) + } + } + cc.C.subject.networks = &cc.internalSubjectNetworks[0] + cc.C.subject.networkCount = C.uint(len(c.Subject.Networks)) + } + + if len(c.Subject.Certificates) > 0 { + cc.C.subject.certificates = (**C.uint8_t)(unsafe.Pointer(&c.Subject.Certificates[0])) + cc.C.subject.certificateCount = C.uint(len(c.Subject.Certificates)) + } + + if len(c.Subject.UpdateURLs) > 0 { + cc.internalSubjectUpdateURLs = make([]*C.char, len(c.Subject.UpdateURLs)) + cc.internalSubjectUpdateURLsData = make([][]byte, len(c.Subject.UpdateURLs)) + for i, u := range c.Subject.UpdateURLs { + cc.internalSubjectUpdateURLsData[i] = stringAsZeroTerminatedBytes(u) + cc.internalSubjectUpdateURLs[i] = (*C.char)(unsafe.Pointer(&cc.internalSubjectUpdateURLsData[0])) + } + cc.C.subject.updateURLs = (**C.char)(unsafe.Pointer(&cc.internalSubjectUpdateURLs[0])) + cc.C.subject.updateURLCount = C.uint(len(c.Subject.UpdateURLs)) + } + + cStrCopy(unsafe.Pointer(&cc.C.subject.name.serialNo[0]), CertificateMaxStringLength+1, c.Subject.Name.SerialNo) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.commonName[0]), CertificateMaxStringLength+1, c.Subject.Name.CommonName) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.country[0]), CertificateMaxStringLength+1, c.Subject.Name.Country) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.organization[0]), CertificateMaxStringLength+1, c.Subject.Name.Organization) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.unit[0]), CertificateMaxStringLength+1, c.Subject.Name.Unit) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.locality[0]), CertificateMaxStringLength+1, c.Subject.Name.Locality) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.province[0]), CertificateMaxStringLength+1, c.Subject.Name.Province) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.streetAddress[0]), CertificateMaxStringLength+1, c.Subject.Name.StreetAddress) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.postalCode[0]), CertificateMaxStringLength+1, c.Subject.Name.PostalCode) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.email[0]), CertificateMaxStringLength+1, c.Subject.Name.Email) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.url[0]), CertificateMaxStringLength+1, c.Subject.Name.URL) + cStrCopy(unsafe.Pointer(&cc.C.subject.name.host[0]), CertificateMaxStringLength+1, c.Subject.Name.Host) + + if len(c.Subject.UniqueID) > 0 { + cc.C.subject.uniqueId = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueID[0])) + cc.C.subject.uniqueIdSize = C.uint(len(c.Subject.UniqueID)) + if len(c.Subject.UniqueIDProofSignature) > 0 { + cc.C.subject.uniqueIdProofSignature = (*C.uint8_t)(unsafe.Pointer(&c.Subject.UniqueIDProofSignature[0])) + cc.C.subject.uniqueIdProofSignatureSize = C.uint(len(c.Subject.UniqueIDProofSignature)) + } + } + + if c.Issuer != nil { + if !c.Issuer.initCIdentityPtr() { + return nil + } + cc.C.issuer = c.Issuer.cid + } + + cStrCopy(unsafe.Pointer(&cc.C.issuerName.serialNo[0]), CertificateMaxStringLength+1, c.IssuerName.SerialNo) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.commonName[0]), CertificateMaxStringLength+1, c.IssuerName.CommonName) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.country[0]), CertificateMaxStringLength+1, c.IssuerName.Country) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.organization[0]), CertificateMaxStringLength+1, c.IssuerName.Organization) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.unit[0]), CertificateMaxStringLength+1, c.IssuerName.Unit) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.locality[0]), CertificateMaxStringLength+1, c.IssuerName.Locality) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.province[0]), CertificateMaxStringLength+1, c.IssuerName.Province) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.streetAddress[0]), CertificateMaxStringLength+1, c.IssuerName.StreetAddress) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.postalCode[0]), CertificateMaxStringLength+1, c.IssuerName.PostalCode) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.email[0]), CertificateMaxStringLength+1, c.IssuerName.Email) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.url[0]), CertificateMaxStringLength+1, c.IssuerName.URL) + cStrCopy(unsafe.Pointer(&cc.C.issuerName.host[0]), CertificateMaxStringLength+1, c.IssuerName.Host) + + if len(c.ExtendedAttributes) > 0 { + cc.C.extendedAttributes = (*C.uint8_t)(unsafe.Pointer(&c.ExtendedAttributes[0])) + cc.C.extendedAttributesSize = C.uint(len(c.ExtendedAttributes)) + } + + cc.C.maxPathLength = C.uint(c.MaxPathLength) + + if len(c.Signature) > 0 { + cc.C.signature = (*C.uint8_t)(unsafe.Pointer(&c.Signature[0])) + cc.C.signatureSize = C.uint(len(c.Signature)) + } + + return &cc +} diff --git a/pkg/zerotier/endpoint.go b/pkg/zerotier/endpoint.go index c010b0954..b6ace8e23 100644 --- a/pkg/zerotier/endpoint.go +++ b/pkg/zerotier/endpoint.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/errors.go b/pkg/zerotier/errors.go index d3c97e7e8..daeb07e73 100644 --- a/pkg/zerotier/errors.go +++ b/pkg/zerotier/errors.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/fingerprint.go b/pkg/zerotier/fingerprint.go index 6269464e0..e16138208 100644 --- a/pkg/zerotier/fingerprint.go +++ b/pkg/zerotier/fingerprint.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/identity.go b/pkg/zerotier/identity.go index 8b11afddf..1e15c2ddb 100644 --- a/pkg/zerotier/identity.go +++ b/pkg/zerotier/identity.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/inetaddress.go b/pkg/zerotier/inetaddress.go index c8317907d..bb48c377b 100644 --- a/pkg/zerotier/inetaddress.go +++ b/pkg/zerotier/inetaddress.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/localconfig.go b/pkg/zerotier/localconfig.go index 1e7e87687..827090ffb 100644 --- a/pkg/zerotier/localconfig.go +++ b/pkg/zerotier/localconfig.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/locator.go b/pkg/zerotier/locator.go index c0fc23926..5b7f02b30 100644 --- a/pkg/zerotier/locator.go +++ b/pkg/zerotier/locator.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/mac.go b/pkg/zerotier/mac.go index 0d54f6061..4ce50eb54 100644 --- a/pkg/zerotier/mac.go +++ b/pkg/zerotier/mac.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/misc.go b/pkg/zerotier/misc.go index ee3450225..7b41d94f5 100644 --- a/pkg/zerotier/misc.go +++ b/pkg/zerotier/misc.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. @@ -259,3 +259,27 @@ func ipClassify(ip net.IP) int { return ipClassificationNone } + +// stringAsZeroTerminatedBytes creates a C string but as a Go []byte +func stringAsZeroTerminatedBytes(s string) (b []byte) { + if len(s) == 0 { + b = []byte{0} // single zero + return + } + sb := []byte(s) + b = make([]byte, len(sb) + 1) + copy(b, sb) + // make() will zero memory, so b[len(sb)+1] will be 0 + return +} + +// cStrCopy copies src into dest as a zero-terminated C string +func cStrCopy(dest unsafe.Pointer, destSize int, src string) { + sb := []byte(src) + b := C.GoBytes(dest, C.int(destSize)) + if len(sb) > (destSize - 1) { + sb = sb[0:destSize - 1] + } + copy(b[:], sb[:]) + b[len(sb)] = 0 +} diff --git a/pkg/zerotier/multicastgroup.go b/pkg/zerotier/multicastgroup.go index c44b5ba69..98b6b64ec 100644 --- a/pkg/zerotier/multicastgroup.go +++ b/pkg/zerotier/multicastgroup.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/nativetap.go b/pkg/zerotier/nativetap.go index 403961dd3..1efe6c0ca 100644 --- a/pkg/zerotier/nativetap.go +++ b/pkg/zerotier/nativetap.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/network.go b/pkg/zerotier/network.go index 18c945fe3..3f6da0ad0 100644 --- a/pkg/zerotier/network.go +++ b/pkg/zerotier/network.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/node.go b/pkg/zerotier/node.go index d3c006494..910e78e2c 100644 --- a/pkg/zerotier/node.go +++ b/pkg/zerotier/node.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/osdep-posix.go b/pkg/zerotier/osdep-posix.go index d48ec1b8e..13a5adc33 100644 --- a/pkg/zerotier/osdep-posix.go +++ b/pkg/zerotier/osdep-posix.go @@ -1,7 +1,7 @@ // +build !windows /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/osdep-windows.go b/pkg/zerotier/osdep-windows.go index ecfca458f..d2dcf6189 100644 --- a/pkg/zerotier/osdep-windows.go +++ b/pkg/zerotier/osdep-windows.go @@ -1,7 +1,7 @@ // +build windows /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/path.go b/pkg/zerotier/path.go index f97d6e395..18c9fcf36 100644 --- a/pkg/zerotier/path.go +++ b/pkg/zerotier/path.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/peer.go b/pkg/zerotier/peer.go index 5f5a23154..5e6c92da7 100644 --- a/pkg/zerotier/peer.go +++ b/pkg/zerotier/peer.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/route.go b/pkg/zerotier/route.go index 262773a48..de45cebce 100644 --- a/pkg/zerotier/route.go +++ b/pkg/zerotier/route.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/sizelimitwriter.go b/pkg/zerotier/sizelimitwriter.go index fb3a51f88..ea72edc48 100644 --- a/pkg/zerotier/sizelimitwriter.go +++ b/pkg/zerotier/sizelimitwriter.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory. diff --git a/pkg/zerotier/tap.go b/pkg/zerotier/tap.go index 29c119d98..e4c214b1a 100644 --- a/pkg/zerotier/tap.go +++ b/pkg/zerotier/tap.go @@ -1,5 +1,5 @@ /* - * Copyright (c)2013-2020 ZeroTier, Inc. + * Copyright (C)2013-2020 ZeroTier, Inc. * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file in the project's root directory.