前言 这是加密与认证系列的第五篇文章了,本来我是想把自建证书和nginx配置https访问总结到一起的,但是在实际操作的过程中我发现了很多细小的知识点,有些还是挺有意思的,这是一个不断自我提问不断寻求答案的过程,随着扩展的内容越来越多,我决定这篇只写自建CA和签名SSL证书这部分,至于nginx配置https访问放到后面再写吧。 相信点进这篇文章的人应该知道为什么要自建CA和自签名SSL证书了,因为买现成的SSL证书挺贵的,SSL证书通常有三种类型:域名级(DV)、企业级(OV)、增强级(EV),价格从每年几百元到上万元不等,再细分的话还有单域名证书、通配符证书、多域名证书等等,有些证书还可以追加域名。 这笔费用对于大厂来说可能不算什么,但是对于小产品来说,即使选择最便宜的证书也是一笔开销,比如在上一篇《根证书的应用和信任基础》提到的12306官网在2017以前使用的也是用的自签名证书,一般正式产品总会咬咬牙买个证书,但是如果是本地测试,或者局域内网的使用的产品使用自建的证书就足够了,相当于我们配了临时证书资源在开发新功能,等到真正对外发布时再替换成购买的证书也来的及,所以接下来我们就一起走一遍自建证书的流程。 一键生成自签名证书 总有心急的人想吃热豆腐,所以我把用到的命令写了一个脚本,只要输入几个自定义密码就可以完成CA证书和SSL证书的创建,前提是在你的电脑安装了openssl命令,在ubuntu上系统上默认就有,没有的自己安装一下吧。 命令脚本 将下列命令放到shell脚本文件onekeyssl中执行即可 #!/bin/bash read -p "Enter your domain or ip [www.example.com/10.10.49.172]: " INPUT echo "1. Create ca private key..." openssl genrsa -des3 -out selfca.key 2048 echo "2. Create ca root certificate..." openssl req -new -x509 -days 3650 -key selfca.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA" -out selfca.crt echo "3. Create server key and certificate signing request..." openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=$INPUT" -out server.csr echo "4. Sign SSL certificate..." openssl x509 -req -extfile <(printf "subjectAltName=IP:$INPUT") -days 3650 -in server.csr -CA selfca.crt -CAkey selfca.key -CAcreateserial -out server.crt echo "5. Create end, next work..." echo "Copy server.crt and server.key to your server machine" 执行结果 $ ./onekeyssl.sh Enter your domain or ip [www.example.com/10.10.49.172]: 10.10.19.1 1. Create ca private key... Generating RSA private key, 2048 bit long modulus (2 primes) ..................................................+++++ .....................................+++++ e is 65537 (0x010001) Enter pass phrase for selfca.key:【输入自定义密码】 Verifying - Enter pass phrase for selfca.key:【重复密码】 2. Create ca root certificate... Enter pass phrase for selfca.key:【重复密码】 3. Create server key and certificate signing request... Generating a RSA private key .............................................................+++++ ..........+++++ writing new private key to 'server.key' ----- 4. Sign SSL certificate... Signature ok subject=C = CN, ST = BJ, L = BJ, O = MyRootServer, OU = MyServer, CN = 10.10.19.1 Getting CA Private Key Enter pass phrase for selfca.key:【重复密码】 5. Create end, next work... Copy server.crt and server.key to your server machine 分步来看看自建证书的过程 整个过程分为自建CA和自签名SSL证书两部分: 自建CA:并不是要你自己搭建一个CA中心,这里的CA其实指的是创建自己的CA根证书,这样可以给其他人签署证书,但是这个CA根证书是你自己创建的,没有得到互联网的承认,也不会被正规CA认可,所以不具备通用和有效性,一般可以在内部网络使用。 自签名SSL证书:一般来说,我们的证书是要发给权威机构CA进行验证签署的,但是自签证书,就是自己给自己签署生成一份CA证书,或者用自建的CA根证书来签发的SSL证书,同样不具备互联网的通用和有效性,一般只用于测试环境或内部网络。 自建CA根证书 自建CA根证书也是分成两步 生成CA私钥 openssl genrsa -des3 -out selfca.key 2048 1 这条命令使用 OpenSSL 工具生成一个带有Triple-DES(3DES)加密的密码保护的2048位RSA私钥文件,各个参数的含义如下: openssl: OpenSSL 工具的命令行执行器。 genrsa: 生成RSA密钥的命令。 -des3: 使用Triple-DES算法对生成的私钥进行加密,这会在生成私钥时要求你设置一个密码,以便在每次使用私钥时都需要提供密码。 -out selfca.key: 指定生成的私钥的输出文件名为 selfca.key,私钥文件将被保存在当前工作目录中。 2048: 指定生成的RSA私钥的位数为2048位,这是一种常见的安全密钥长度。 其中密码这一项在生成CA证书时我们是想加的,运行命令后需要输入一个自定义密码两次,以后每次使用这个私钥都要输入密码,但是在很多文章中你会发现他们有一步是要删除密码,原因是在一些自动化部署场景中,去掉私钥密码可以避免手动输入密码,使整个过程更加自动化,比如配置到Apache或者Nginx中时不必每次启动时输入密码,所以我们在后面生成服务器私钥时就不使用密码了。 带有密码的私钥内容 -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,2D6A221FF66727E0 vEzhQnjsKVBLw6tPNo6Dx7D8CyzhZdZYgfxuZBYP30cLWOORTpsS1q0txNMCaWoy S79k0+qTgENne2oirALiCnPB5Rzf3vO6gv/KSScvEnGrZ6Q57i3xObhLYzCtKOAg E6wSBBfbeC6cXczAFZ2ehnM42+Cv/9BX829X7BnbylNbaV1VXQTaEsmo+uWwx9dZ … C2udyFqENooTB7n1Qbtm3Fsruwgk/0IM3vSRk41/EWADabWs4tR/uXQmCPyxouHI xhT3U4EeabyY8dyjSRCkzKPIEFl2HwnYQHZcDVUPD52uHEvA5M7c1QNgX2VmTXzP AgSijAZHDrh6QWa+R9eqUVQShY4mAN7c1sv1or4ZckV7jQTbIBjUGcjhX1TooxX0 /RE/GLodSqD8wCkxjgD7uxy93oOLuV/9iDDsrI7VMrs5jlKhKEuPozc+Y+hERRBm UUMbAE2JBW+jD/JzkmXL8w4AGU8wHeRI/FqKQXLbP6v3h+Yb4zP/aOVZ5mdWlHWT 1+BykB3qgKUqcn+FmRbodvK8C1G1opDchyomCToHzCGTDqAAcRPoNiB5z3jB+yPC M0m83wI4rWYPghWL4hT7aZgI8l2xwTJfJfyJ+/6MfBZgh/qa4t703A== -----END RSA PRIVATE KEY----- 不带密码的私钥内容 -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA6OCPgi1pUWdkS9DdR2mk6QJsE9i6rCgaDuk+xyi8Sdxp2u8r f81ZrK4xUNUNTX8+lnj5WeolJ/Hk1o9I659oPkbWuw7yyuCBFbZ9m3goZCt2w+lc csLw6o6XyGTUiptcgB/GmGcd/ua3REAt3l6uYn32vjeit5oX5xsmsUKbwpIH/B81 nMohd/t6m9c0h2mcVnUYDmUsV+hmgdASvkTSmvqHOUwV1qX/pQNgjR+auLiezoza LmVkvtSI9/tX6sqtlyROn7ZFsUHJbYuyfOekqLCiY5Wo5ocSTqAd4n/JYmjA6anI YGDXbLcP+075ZgkHSoR9ab4uFtghStx99QYwywIDAQABAoIBAQDWeWryE2y5wiVH … SdwHzniXCpBpNYB6XoV57bPpQiSCqVyT9Owd0A9csZf4905dOZg+/25K2TFmv7gG fHN/4EkCgYEAz7VrytExyCm1B+7sFln7c1hjy5wzNaW2tYi08szvErJkpe3jz9HH MLbTn+DrXZu76nsiXfQbTl7SpPQJptHctHx7K+9mykDaJNGDDNmJRKdwi8cfINrD yYPab+aojwU1FZtF8EEXKjnzWIvmM8FO71ej+COUOmDxWCsDbpoHyhA= -----END RSA PRIVATE KEY----- 生成CA自签名证书 openssl req -new -x509 -days 3650 -key selfca.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA" -out selfca.crt 1 这条命令使用 OpenSSL 工具生成自签名根证书(Root Certificate),各个参数的含义如下: openssl req: 这是 OpenSSL 工具中用于处理证书签署请求(CSR)的命令。 -new: 表示创建新的 CSR。 -x509: 表示生成自签名的 X.509 证书,而不是生成 CSR。 -days 3650: 设置证书的有效期为 3650 天(10 年)。 -key selfca.key: 指定用于生成证书的私钥文件为 selfca.key。 -subj "/C=CN/ST=BJ/L=BJ/O=MyRootCA/OU=MyCA/CN=CA": 设置证书主题(Subject)的信息。这里使用了简化的 Distinguished Name (DN),包括了国家(C=CN)、省/州(ST=BJ)、城市(L=BJ)、组织(O=MyRootCA)、组织单位(OU=MyCA)、通用名称(CN=CA)等信息。 -out selfca.crt: 指定生成的证书文件的输出路径和文件名,这里为 selfca.crt。 至此我们就生成了一个自签名的CA根证书,如果把它加入到操作系统或浏览器的信任列表中,那么之后由他签发的SSL证书都可以被信任了,接下来我们开始用它来签发SSL证书。 自签名SSL证书 这个过程主要包括生成服务器密钥、构建签名请求和用CA签名证书三部分,其中前两步可以合并为一步: 生成服务器私钥和证书申请文件CRS $ openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=10.10.49.172" -out server.csr 1 这条命令使用 OpenSSL 工具生成证书签署请求(CSR),各个参数的含义如下: openssl req: 这是 OpenSSL 工具中用于处理证书签署请求(CSR)的命令。 -newkey rsa:2048: 创建一个新的 RSA 密钥对,其中包括一个 2048 位的 RSA 私钥和相应的公钥。 -nodes: 生成的私钥不使用密码进行加密。这意味着私钥文件 server.key 将不需要密码才能访问。 -keyout server.key: 指定生成的私钥文件的输出路径和文件名,这里为 server.key。 -subj "/C=CN/ST=BJ/L=BJ/O=MyRootServer/OU=MyServer/CN=10.10.49.172": 设置证书主题(Subject)的信息。这里使用了简化的 Distinguished Name (DN),包括了国家(C=CN)、省/州(ST=BJ)、城市(L=BJ)、组织(O=MyRootServer)、组织单位(OU=MyServer)、通用名称(CN=10.10.49.172)等信息。通用名称(CN)通常用于指定服务器的主机名或 IP 地址。 -out server.csr: 指定生成的证书签署请求文件的输出路径和文件名,这里为 server.csr。 使用CA根证书签名SSL证书 $ openssl x509 -req -extfile <(printf "subjectAltName=IP:10.10.49.172") -days 3650 -in server.csr -CA selfca.crt -CAkey selfca.key -CAcreateserial -out server.crt 1 这条命令使用 OpenSSL 工具签署证书签署请求(CSR)并生成证书,并且带有SAN信息,各个参数的含义如下: openssl x509: 这是 OpenSSL 工具中用于处理 X.509 证书的命令。 -req: 表示输入的文件是证书签署请求(CSR)。 -extfile <(printf "subjectAltName=IP:10.10.49.172[,DNS:<YOUR_DOMAIN>,...]"): 使用扩展文件,该文件包含了额外的证书扩展信息。在这里,subjectAltName 扩展用于指定主体的备用名称(Subject Alternative Name),这里指定了 IP 地址 10.10.49.172。你也可以在方括号中添加其他主机名或 IP 地址,用逗号分隔。 -days 3650: 设置生成的证书的有效期为 3650 天(10 年)。 -in server.csr: 指定输入的证书签署请求文件,这里为 server.csr。 -CA selfca.crt: 指定用于签署证书的 CA 证书文件,这里为 selfca.crt。 -CAkey selfca.key: 指定用于签署证书的 CA 私钥文件,这里为 selfca.key。 -CAcreateserial: 创建一个新的序列号文件,该文件用于跟踪 CA 签署的证书的唯一性。 -out server.crt: 指定生成的证书文件的输出路径和文件名,这里为 server.crt。 SAN(Subject Alternative Name)是 X.509 证书的一种扩展,用于指定除主题(Subject)之外的其他标识信息。主要用于解决传统的基于主题(Subject)的身份验证方式可能存在的限制,特别是在一个证书需要覆盖多个主机名或 IP 地址的情况下。 SAN 扩展可以包含多个备用名称(Alternative Name),这些备用名称可以是: DNS Name(域名): 用于指定主机名,可以是域名或子域名。 IP Address(IP 地址): 用于指定 IP 地址。 Email Address(电子邮件地址): 用于指定电子邮件地址。 URI(统一资源标识符): 用于指定统一资源标识符。 Directory Name(目录名称): 用于指定目录名。 在实际使用中,SAN 可以解决多种问题,例如: 多域 SSL 证书: 当一个 SSL 证书需要覆盖多个域名时,可以使用 SAN 扩展。 IP 地址验证: 当需要确保证书可以与特定 IP 地址关联时,可以使用 SAN 扩展。 多级子域名: 当证书需要覆盖主域和多级子域时,可以使用 SAN 扩展。 SAN 扩展通常在证书签署请求(CSR)或证书颁发时指定,并在证书中进行存储。在 OpenSSl 命令中,使用 -extfile 选项指定一个包含 SAN 信息的文件,通过该文件可以指定多个备用名称。 最终的文件列表 至此CA根证书和自签名SSL证书就生成好了,我们一共收获到了5个文件,作用分别如下: selfca.key:CA私钥,用于后续签名SSL证书 selfca.crt:CA根证书,用于后续签名SSL证书,需要加入到操作系统或浏览器的信任列表中 server.key:服务器私钥,需要配置到https服务,比如Apache和Nginx配置文件中 server.csr:证书签署请求文件,后续没用了 server.crt:自签名SSL证书,需要配置到https服务,比如Apache和Nginx配置文件中,这就是代表服务器的身份证件 如果想查询证书信息同样可以使用 openssl 命令查询 $ openssl x509 -text -noout -in server.crt Certificate: Data: Version: 3 (0x2) Serial Number: 56:76:35:2c:61:a5:a0:7c:8c:3b:26:93:db:c2:95:a7:18:f9:95:f0 Signature Algorithm: sha256WithRSAEncryption Issuer: C = CN, ST = BJ, L = BJ, O = MyRootCA, OU = MyCA, CN = CA Validity Not Before: Nov 30 14:43:32 2023 GMT Not After : Nov 27 14:43:32 2033 GMT Subject: C = CN, ST = BJ, L = BJ, O = MyRootServer, OU = MyServer, CN = 10.10.17.2 Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:b3:41:7c:58:c7:13:c1:c9:af:5b:d6:7d:cb:9a: 04:f1:73:5f:60:c4:43:df:4e:26:f5:4d:da:48:f6: 4f:13:90:c0:6f:17:a8:44:00:9c:3f:a5:f1:5e:6c: 28:15:74:5f:c7:c5:0c:bf:a1:7b:b3:31:ac:7c:67: 59:58:f6:33:cd:bb:a6:45:85:98:21:c1:79:2c:b9: d2:46:9e:9c:ef:59:ba:d4:0d:fb:4c:86:81:a1:4c: a8:47:d7:4c:cf:13:89:8b:d2:6d:68:85:8f:10:26: 87:15:73:ee:e6:14:36:f2:09:d3:c9:2f:f5:bf:c6: e1:ec:ee:54:06:82:83:ee:f7:70:e1:50:2e:a0:44: ce:e1:a4:f9:68:4e:e5:b4:be:39:77:02:1b:ca:c2: c9:55:72:d1:56:ca:e4:47:67:54:1b:d8:a2:83:29: 02:0a:1a:b3:81:22:a0:fb:84:cf:d7:43:1c:be:37: bf:9e:04:95:ad:2e:20:ca:2f:04:c8:ef:92:26:7f: 5c:f9:1c:94:6d:e5:7b:93:2a:51:fa:d2:e1:a8:87: d4:f8:aa:6d:38:d0:6a:19:8f:48:9d:3a:c3:40:bd: e9:00:ff:cf:f6:67:08:7e:ec:f2:e6:3b:b1:f5:c9: ea:f9:52:5c:f4:68:6b:ee:15:b4:fc:ce:44:6d:86: 4d:ef Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Alternative Name: IP Address:10.10.17.2 Signature Algorithm: sha256WithRSAEncryption 26:c8:f8:bd:dc:a3:67:86:e9:a9:81:ce:1a:be:a4:be:c2:f0: 10:cf:9f:30:1a:a8:40:ee:1a:41:ab:87:33:7e:35:2c:f0:3b: 9b:62:79:82:fe:7c:63:6e:e8:65:a7:2d:2e:aa:d9:73:2d:58: a1:b6:70:ae:33:5f:28:27:52:a0:06:d9:37:d4:a8:70:85:73: 34:a4:a0:f4:f0:da:4c:9a:61:ab:74:9d:2f:ff:56:be:e4:7a: c8:af:7e:f6:8a:4c:52:dc:13:db:9a:33:63:cb:79:b0:18:78: f4:9e:af:dd:02:54:0b:94:b0:94:29:77:92:ae:7a:35:ca:00: 28:bc:be:c1:a1:1a:47:1b:72:5d:2c:1d:0e:79:e6:45:0e:3e: e1:25:dc:4c:e0:cb:a0:2a:ad:98:02:d1:e3:92:68:5a:37:89: 5e:36:54:ec:ed:8a:b4:8b:f7:26:a9:4e:89:15:5e:ed:b1:26: 45:b4:03:99:37:74:c1:4c:d4:11:eb:42:3d:a4:3f:a8:30:99: a0:61:08:85:f7:9e:4e:15:21:37:c3:61:ea:7e:24:3d:73:85: 44:28:b1:be:b5:27:26:df:38:49:43:ce:b9:96:f9:48:d4:15: 4b:49:e6:6c:9e:e1:21:d1:25:af:da:76:e2:7e:ca:da:9e:30: 60:77:53:70 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 相关名词 写到这里虽然说了很多,但感觉还是有点不太清楚,问题出在哪里呢?貌似很多名字直接把初学者干蒙了,所以对于一些认证的名次我再简单总结一下: SSL/TLS协议 SSL: Secure Socket Layer 是由网景公司创建的,一种在互联网上提供密钥传输机制或者叫做协议。其主要目标是保证两个应用间通信数据的保密性和可靠性,可在服务器端和用户端同时支持的一种加密算法。 TLS:Transport Lanyer Security,由于网景公司的没落,IETF将SSL进行标准化,1999年公布了TLS标准文件。常用的版本:TLS v1(与SSL v3基本相同) 证书颁发机构(CA) CA(Certificate Authority)是一个负责签发和管理数字证书的可信任实体。数字证书用于在计算机网络上进行身份验证和加密通信。CA 的主要职责包括验证证书请求者的身份,并签发数字证书,确认公钥和身份之间的关联。 以下是 CA 的主要特征和职责: 身份验证: CA 负责验证证书请求者的身份。这通常涉及验证请求者拥有特定域名或 IP 地址的控制权。验证可以通过多种方式进行,包括域验证、组织验证等。 签发证书: 一旦验证通过,CA 将签发数字证书。数字证书包含了一对密钥中的公钥,以及相关的身份信息。私钥通常由证书的所有者保管,而公钥和证书信息则被 CA 所签署。 证书吊销: CA 负责在需要时吊销证书。证书可能需要吊销的原因包括证书的所有者不再控制相关私钥、证书的私钥被泄露、证书的所有者不再合法等。 维护证书撤销列表(CRL): CA 维护一个证书撤销列表,其中包含吊销的证书的信息。这允许其他实体检查某个证书是否已被吊销。 数字签名: CA 使用其私钥对签发的证书进行数字签名,以确保证书的完整性和真实性。其他实体可以使用 CA 的公钥来验证数字签名。 信任链: CA 的根证书被内置到操作系统和浏览器中,形成了信任链。当服务器或服务端提供由 CA 签发的证书时,客户端可以通过信任链验证证书的真实性。 数字证书(Certificate) 数字证书,是一种用于电脑的身份识别机制。由数字证书颁发机构(CA)对使用私钥创建的签名请求文件做的签名(盖章),表示CA结构对证书持有者的认可。 X.509证书包含三个文件:后缀分别为key,csr和crt,在密码学中,X.509是一个标准,规范了公开秘钥认证、证书吊销列表、授权凭证、凭证路径验证算法等 key:是服务器上的私钥文件,用于对发送给客户端数据的加密,以及对从客户端接收到数据的解密 csr:是证书签名请求文件,用于提交给证书颁发机构(CA)对证书签名 crt:是由证书颁发机构(CA)签名后的证书,或者是开发者自签名的证书,包含证书持有人的信息,持有人的公钥,以及签署者的签名等信息 .pem文件 在生成密钥的过程中通常会涉及到.pem文件,.pem 是一种通用的文件扩展名,表示文件内容遵循 Privacy Enhanced Mail (PEM) 格式。PEM 格式是一种基于文本的编码格式,常用于存储和传输数据,特别是涉及加密和证书的数据。PEM 格式的文件使用 ASCII 编码,以便于阅读和传输。 PEM 文件通常包含的信息类型有: 证书(Certificate): 通常以 .pem 扩展名保存,包含用于公钥加密和身份验证的数字证书。 私钥(Private Key): 也可以以 .pem 扩展名保存,包含用于对数据进行解密和签名的私钥。 证书请求(Certificate Signing Request,CSR): 包含有关证书请求者的信息,通常用于向证书颁发机构(CA)请求签发数字证书。 密钥和证书的捆绑(Bundle): 有时,PEM 文件还可以包含密钥和证书的捆绑,以便在一个文件中同时包含私钥和相关的证书。 PEM 格式的文件采用 Base64 编码,同时包含用于描述文件内容的文本标记。标记通常以 -----BEGIN ...----- 和 -----END ...----- 的形式出现,标记之间的内容是经过 Base64 编码的二进制数据。 示例: -----BEGIN CERTIFICATE----- MIID... ... ... (Base64-encoded data) ... -----END CERTIFICATE----- 1 2 3 4 5 6 不同的应用程序和系统可能会使用 .pem 扩展名来表示各种类型的文件,因此需要根据上下文和文件内容来确定其确切的含义。 总结 自建CA根证书和生成SSL签名证书都可以通过 openssl 命令来完成 自建CA根证书结果会得到selfca.key和selfca.crt两个文件,名字可以自定义,用于后续签名服务器SSL证书 生成SSL签名证书的结果会得到server.key、server.csr、server.csr三个文件,只要把server.key和server.csr配置到服务器就好了 生成server.key时一般为了自动化维护不会设置密码,如果为了安全确实需要密码的话,可以配置到密码文件中防止服务重启时打断流程 网络的世界里证书就是身份证,在这个环境下你总要无条件信点啥,比如你的操作系统和浏览器 备注 不知道你有没有注意到,用私钥签名根证书的时候并没有使用公钥,按道理说签名的时候会把公钥放到签名证书中才对,为什么这里没有呢?那是因为对于 RSA 算法,从私钥可以提取公钥,因为私钥包含了模数(modulus)和私钥指数(private exponent)。然而,从公钥(包含模数和公钥指数)推导出私钥,则取决于大数分解问题的难解性,目前尚未找到有效的算法在合理的时间内解决大整数的分解问题。所以说公钥是可以从私钥从得到的,所以不必单独获取。 |
GMT+8, 2024-10-16 10:07 , Processed in 0.054269 second(s), 19 queries , Gzip On.
Powered by Discuz! X3.5
© 2001-2024 Discuz! Team.