• 熱門專題

基于ejbca community 6.3.1.1構建獨立ca系統管理數字證書

作者:凌承一  發布日期:2016-12-05 20:46:51
Tag標簽:數字證書  系統  
  •   “數字證書”這個名詞相信很多人聽過,但并不了解,“ejbca”可能很多人都沒有聽過

      數字證書(Certificate),就是互聯網通信過程中標志通信各方身份的一個文件,可以理解為“網絡身份證”,主要目的是驗證身份

      ejbca,是一個CA(Certificate Authority)系統軟件,CA是數字證書認證中心的簡稱,主要功能是管理數字證書,包括證書的頒發、銷毀、更新等,ejbca實現了CA規范,因此可以用來管理數字證書

      接下來,筆者將按照ejbca安裝、使用、數字證書使用、web service接口、nginx代理順序逐步介紹一個獨立ca系統完整的建立與使用過程

    centos安裝ejbca-community-6.3.1.1

      ejbca安裝過程算比較復雜了,本文以centos 6.5系統為例介紹安裝過程,其他linux可以參考,windows下的安裝過程幾乎相同,安裝過程使用是ejbca community 6.3.1.1(社區版),安裝過程請嚴格按照以下步驟,不然很容易出錯!

    1、安裝基礎環境

      安裝ejbca需要jdk-1.7以上、ant構建工具、可用的mysql數據庫、jboss-7.1.1,其中jdk、ant、mysql安裝配置過程參考http://www.cnblogs.com/ywlaker/p/6129872.html,如果已經安裝過這些,可以忽略,直接進入以下步驟

    2、安裝啟動jboss

      從jboss官方網站下載jboss安裝包:jboss-as-7.1.1.Final.tar.gz,解壓并配置環境變量

    tar xvf jboss-as-7.1.1.Final.tar.gz -C /usr/java
    vi /etc/profile
    

      追加內容

    #jboss conf
    export JBOSS_HOME=/usr/java/jboss-as-7.1.1.Final
    

      使配置立即生效

    source /etc/profile
    

      啟動jboss,注意最后的&符號,待啟動完成再運行“exit”

    sh /usr/java/jboss-as-7.1.1.Final/bin/standalone.sh &
    exit
    

      這樣jboss就運行在后臺了,以下命令查看jboss進程并關閉

    ps -ef|grep jboss
    kill -9 進程號
    

    3、配置jboss的mysql數據源

      創建目錄,然后在該目錄下創建module.xml

    mkdir -p /usr/java/jboss-as-7.1.1.Final/modules/com/mysql/main
    cd /usr/java/jboss-as-7.1.1.Final/modules/com/mysql/main
    vi module.xml
    

      module.xml內容如下

    <?xml version='1.0' encoding='UTF-8'?>
    <module xmlns='urn:jboss:module:1.0' name='com.mysql'>
    	<resources>
    		<resource-root path='mysql-connector-java-5.1.27.jar'/>
    	</resources>
    	<dependencies>
    		<module name='javax.api'/>
    		<module name='javax.transaction.api'/>
    	</dependencies>
    </module>
    

      下載mysql的驅動包mysql-connector-java-5.1.27.jar,放在/usr/file目錄,然后拷貝到當前目錄

    cp /usr/file/mysql-connector-java-5.1.27.jar ./
    

      打開新的shell窗口,運行

    sh /usr/java/jboss-as-7.1.1.Final/bin/jboss-cli.sh -c
    

      如果是“disconnect”狀態,先輸入“connect”,多回車幾次后,運行下面命令

    /subsystem=datasources/jdbc-driver=com.mysql.jdbc.Driver:add(driver-name=com.mysql.jdbc.Driver,driver-class-name=com.mysql.jdbc.Driver,driver-module-name=com.mysql,driver-xa-datasource-class-name=com.mysql.jdbc.jdbc.jdbc2.optional.MysqlXADataSource)
    :reload
    

    4、安裝配置ejbca

      從ejbca官方網站下載ejbca安裝包:ejbca_ce_6_3_1_1.zip,放在/usr/file目錄,解壓,準備修改配置

    unzip /usr/file/ejbca_ce_6_3_1_1.zip -d /usr/java
    cd /usr/java
    mv ejbca_ce_6_3_1_1 ejbca-ce-6.3.1.1
    cd /usr/java/ejbca-ce-6.3.1.1/conf/
    

      1、修改ejbca.properties

    mv ejbca.properties.sample ejbca.properties
    vi ejbca.properties
    

      修改如下內容

    appserver.home=/usr/java/jboss-as-7.1.1.Final
    appserver.type=jboss
    

      2、修改database.properties

    mv database.properties.sample database.properties
    vi database.properties
    

      修改如下內容

    # dataSource
    datasource.jndi-name=jboss/datasources/MySqlDS
    # mysql info
    database.name=mysql
    database.url=jdbc:mysql://127.0.0.1:3306/ejbca?characterEncoding=UTF-8
    database.driver=com.mysql.jdbc.Driver
    database.username=root
    database.password=root
    

      3、修改install.properties

    mv install.properties.sample install.properties
    vi install.properties
    

      修改如下內容

    #設置ca名稱
    ca.name=test
    #設置ca信息
    ca.dn=CN=test,O=test,C=cn
    

      4、修改cesecore.properties、jaxws.properties,不需要修改內容

    mv cesecore.properties.sample cesecore.properties
    mv jaxws.properties.sample jaxws.properties
    

      5、修改web.properties

    mv web.properties.sample web.properties
    vi web.properties
    

      修改如下內容

    #密碼最好6位
    superadmin.password=123456
    superadmin.cn=superadmin
    httpsserver.hostname=ca.test.com
    httpsserver.dn=CN=${httpsserver.hostname},O=test,C=cn
    

    5、部署ejbca到jboss

      首先,在配置的mysql中創建“ejbca”數據庫,編碼“utf-8”,然后正式用ant構建ejbca并安裝到jboss

    cd /usr/java/ejbca-ce-6.3.1.1
    
    ant clean deploy
    ant install
    ant deploy-keystore
    

      deploy用ant部署,install生成證書,deploy-keystore將證書部署到jboss,前兩步所需時間較長,過程中如需輸入,請直接回車

    6、配置jboss開啟https

      打開新的shell窗口,運行

    sh /usr/java/jboss-as-7.1.1.Final/bin/jboss-cli.sh -c
    

      如果是“disconnect”狀態,運行“connect”,多回車幾次,準備運行下面4部分配置

      第一部分(配置任意主機可訪問)

    /interface=http:add(inet-address='0.0.0.0')
    /interface=httpspub:add(inet-address='0.0.0.0')
    /interface=httpspriv:add(inet-address='0.0.0.0')
    /socket-binding-group=standard-sockets/socket-binding=http:add(port='8080',interface='http')
    /subsystem=undertow/server=default-server/http-listener=http:add(socket-binding=http)
    /subsystem=undertow/server=default-server/http-listener=http:write-attribute(name=redirect-socket, value='httpspriv')
    :reload
    

      第二部分(配置證書)

    /core-service=management/security-realm=SSLRealm:add()
    /core-service=management/security-realm=SSLRealm/server-identity=ssl:add(keystore-path='${jboss.server.config.dir}/keystore/keystore.jks', keystore-password='serverpwd', alias='prod-ica1')
    /core-service=management/security-realm=SSLRealm/authentication=truststore:add(keystore-path='${jboss.server.config.dir}/keystore/truststore.jks', keystore-password='changeit')
    /socket-binding-group=standard-sockets/socket-binding=httpspriv:add(port='8443',interface='httpspriv')
    /socket-binding-group=standard-sockets/socket-binding=httpspub:add(port='8442', interface='httpspub')
    :reload
    

      第三部分(配置ssl)

    /subsystem=undertow/server=default-server/https-listener=httpspriv:add(socket-binding=httpspriv, security-realm='SSLRealm', verify-client=REQUIRED)
    /subsystem=undertow/server=default-server/https-listener=httpspub:add(socket-binding=httpspub, security-realm='SSLRealm')
    :reload
    

      第四部分(配置web service)

    /system-property=org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH:add(value=true)
    /system-property=org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH:add(value=true)
    /system-property=org.apache.catalina.connector.URI_ENCODING:add(value='UTF-8')
    /system-property=org.apache.catalina.connector.USE_BODY_ENCODING_FOR_QUERY_STRING:add(value=true)
    /subsystem=webservices:write-attribute(name=wsdl-host, value=jbossws.undefined.host)
    /subsystem=webservices:write-attribute(name=modify-wsdl-address, value=true)
    :reload
    

    使用ejbca管理數字證書

      ejbca安裝完成后,我們就可以使用它管理數字證書了,假設安裝ejbca的服務器地址為:172.17.210.124,我們在windows系統下先配置一個hosts,編輯“C:WindowsSystem32driversetc”目錄下的hosts文件,加入一行

    172.17.210.124 ca.test.com
    

      然后拷貝ejbca服務器“/usr/java/ejbca-ce-6.3.1.1/p12/”目錄下的superadmin.p12文件到windows系統,雙擊該文件開始安裝,默認密碼是“ejbca”,如果配置過程中修改過,請使用修改過的密碼如“123456”

      ejbca系統提供了兩個界面

      管理員界面(需要證書,使用剛才安裝的superadmin證書)

    https://ca.test.com:8443/ejbca/adminweb/
    

      用戶界面

    http://ca.test.com:8080/ejbca/
    

      弄好了超級管理員證書之后,我們開始管理數字證書吧!

    1、用戶注冊

      數字證書是身份認證的載體,身份認證的對象就是“用戶”,數字證書包含“用戶”的基本信息,就想身份證包含了你的姓名等基本信息一樣,注冊過程即是你想ejbca提交個人基本信息

      ejbca管理員界面中,打開“RA Functions”—“Add End Entity”菜單,填寫以下“Required”列打勾的項。

      用戶模板選擇“EMPTY”

      輸入用戶名與密碼

      Common name,如果是服務器用證書,這里請填寫域名

      填寫證書信息,證書模板選擇“ENDUSER”,CA選擇“dev”,Token選擇“P12 file”

      最后點擊“Add”按鈕注冊

    2、下載證書

      注冊完用戶,自然迫不及待要弄到一個證書了,在ejbca用戶界面中,打開“Enroll”—“Create Browser Certificate”菜單

      輸入用戶名和密碼,點擊“OK”按鈕,進入下面的頁面

    “Key length”選擇“2048 bits”;“Certificate profile”選擇“ENDUSER”,點擊“Enroll”按鈕下載證書

    3、吊銷證書

      管理員發現用戶證書被人盜用了,好辦,吊銷它

      ejbca管理員界面中,打開“RA Functions”—“Search End Entities”菜單。“Search end entities with status”處下拉框選擇“All”,點擊右邊的“Search”按鈕查看用戶信息(下圖省略其他列)

      勾選需要吊銷的用戶,點擊表格下方的“Revoke Selected”按鈕,吊銷用戶

    4、更新證書

      用戶上次申請的證書到期了,要更換新的證書

      ejbca管理員界面中,打開“RA Functions”—“Search End Entities”菜單。“Search end entities with status”處下拉框選擇“All”,點擊右邊的“Search”按鈕查看用戶信息(下圖省略其他列)

      點擊需要更新證書用戶的最右邊列中的“Edit End Entity”超鏈接,編輯用戶

      設置“Status”為“New”,點擊右邊的“Save”按鈕。然后輸入新密碼,其他項保持不變,點擊頁面最下方的“Save”按鈕保存設置

    5、根證書

      ejbca作為一個CA,有它自己的根證書

      ejbca用戶界面中,打開“Retrieve”—“Fetch CA Certificates”菜單,可以下載不同格式的根證書

    6、申請tomcat服務器證書

      以上方式可以管理普通用戶用的瀏覽器證書,格式為p12,tomcat服務器用的證書格式為jks,怎么申請呢?

      用戶注冊時,證書模板選擇“SERVER”,CA選擇“dev”,Token選擇“JKS file”,其他項的值不變

      下載證書時,在ejbca用戶界面中,打開“Enroll”—“Create Keystore”菜單,輸入用戶名與密碼,進入下面的頁面

      “Key length”選擇“2048 bits”;“Certificate profile”選擇“SERVER”,點擊“Enroll”按鈕下載證書

      其他服務器證書格式大同小異,相信你可以摸索出來!

    使用web service構建自己的CA系統

      ejbca系統雖然安裝好了,也可以管理數字證書,但是,我們所有的操作都在ejbca提供的界面中執行,先不說全部是英文,單單它里面很多配置項就讓人眼花繚亂,很多配置項要么是固定的,要么是不需要的,因此,最合理的做法是在ejbca之上構建一個中間層,用戶訪問中間層提供的證書管理服務,中間層的服務則使用ejbca實現,正好ejbca提供了完整的web service接口

      中間層只需要提供數字證書的注冊、下載、吊銷、更新即可,更多的功能當然也可以實現,看具體需求了,下面介紹這個中間層的基本實現過程

    1、superadmin.jks證書

      ejbca提供的web service接口需要證書認證,官方源碼給出的例子中使用的就是superadmin超級管理員的證書,但格式是jks,因此我們需要弄到superadmin.jks證書,通過工具轉換是可以的,但ejbca可以直接生成

      對superadmin用戶執行更新操作,保存之前,修改下面項的值為“JKS file”

      按照下載普通用戶證書的步驟下載superadmin的jks格式證書

    2、初始化web service連接

      有了superadmin.jks證書,我們就可以用它來連接web service服務了,但是,必須將web service所需的jar包添加到工程中,這些jar包是下面兩個目錄下的所有jar

    /usr/java/ejbca-ce-6.3.1.1/dist/ejbca-ws-cli/lib
    /usr/java/ejbca-ce-6.3.1.1/dist/ejbca-ws-cli
    

      然后在代碼中初始化web service連接

    public void init() {
    	if (!new File(certPath).exists()) return;
    	
    	CryptoProviderTools.installBCProvider();
    
    	System.setProperty('javax.net.ssl.trustStore', 'd:/superadmin.jks');
    	System.setProperty('javax.net.ssl.trustStorePassword', '123456');
    	System.setProperty('javax.net.ssl.keyStore', 'd:/superadmin.jks');
    	System.setProperty('javax.net.ssl.keyStorePassword', '123456');
    
    	QName qname = new QName('http://ws.protocol.core.ejbca.org/', 'EjbcaWSService');
    
    	try {
    		EjbcaWSService service = new EjbcaWSService(new URL('https://ca.test.com:8443/ejbca/ejbcaws/ejbcaws?wsdl'), qname);
    		EjbcaWS ejbcaWS = service.getEjbcaWSPort();
    	} catch (Exception e) {
    	}
    }
    

      注意:連接地址只能是域名,這個域名是安裝ejbca時為ejbca服務器指定的,所以連接ejbca提供的web service接口服務的機器要配置hosts

    172.17.210.124 ca.test.com
    

      初始化的目的是拿到EjbcaWS對象的實例,接下來的數字證書的注冊、下載等服務均基于它

    3、實現數字證書管理服務

      查看用戶是否已經注冊

    private boolean isExist(String username) throws Exception {
    	UserMatch usermatch = new UserMatch();
    	usermatch.setMatchwith(UserMatch.MATCH_WITH_USERNAME);
    	usermatch.setMatchtype(UserMatch.MATCH_TYPE_EQUALS);
    	usermatch.setMatchvalue(username);
    	try {
    		List<UserDataVOWS> users = ejbcaWS.findUser(usermatch);
    		if (users != null && users.size() > 0) {
    			return true;
    		} else {
    			return false;
    		}
    	} catch (Exception e) {
    		throw new Exception('檢查用戶 ' + username() + ' 是否存在時出錯:' + e.getMessage());
    	}
    }
    

      用戶注冊與更新,用的都是editUser()方法,因此要先判斷是否存在

    public void editUser() throws Exception {
    	UserDataVOWS userData = new UserDataVOWS();
    	userData.setUsername('testname');//用戶名
    	userData.setPassword('123456');//密碼
    	userData.setClearPwd(false);//默認
    	userData.setSubjectDN('CN=' + 'testname'
    			+ ',OU=' + 'testou'
    			+ ',O=' + 'testo'
    			+ ',C=cn'
    			+ ',telephoneNumber=' + '1234567890'
    			);//設置唯一甄別名
    
    	String pattern = 'yyyy-MM-dd HH:mm:ssZZ'; // ISO 8601標準時間格式
    	userData.setStartTime(DateFormatUtils.format(new Date(),pattern));//證書有效起始日期
    	userData.setEndTime(DateFormatUtils.format(DateUtils.addDays(new Date(), 100), pattern));//結束日期
    
    	userData.setCaName('test');//ca名稱,ejbca的名稱
    	userData.setSubjectAltName(null);
    	userData.setEmail('test@test.com');//郵件地址
    	userData.setStatus(UserDataVOWS.STATUS_NEW);//狀態為new
    	userData.setTokenType(UserDataVOWS.TOKEN_TYPE_P12);//設置p12格式證書
    	userData.setEndEntityProfileName('user');//終端實體模板
    	userData.setCertificateProfileName('user');//證書模板
    	try {
    		ejbcaWS.editUser(userData);
    	} catch (Exception e) {
    		throw new Exception(e.getMessage());
    	}
    }
    

      代碼中有幾處值得注意的,終端實體模板“user”和證書模板“user”需要在ejbca管理員界面中配置,并且終端實體模板“user”中要配置開啟“SubjectDN”的屬性如CN、OU、O、C、telephoneNumber等,還要允許修改startTime和endTime

      吊銷證書

    public void revoke(String username) throws ServiceException {
    	try {
    		ejbcaWS.revokeUser(username, RevokedCertInfo.REVOCATION_REASON_UNSPECIFIED, false);
    	} catch (Exception e) {
    	}
    }
    

      創建證書

    private void createCert(String username, String password, String path) throws Exception {
    	FileOutputStream fileOutputStream = null;
    	try {
    		// 創建證書文件
    		KeyStore ksenv = ejbcaWS.pkcs12Req(username, password, null, '2048', AlgorithmConstants.KEYALGORITHM_RSA);
    		java.security.KeyStore ks = KeyStoreHelper.getKeyStore(ksenv.getKeystoreData(), 'PKCS12', password);
    		fileOutputStream = new FileOutputStream(path + File.separator + username + '.p12');
    		ks.store(fileOutputStream, password.toCharArray());
    
    		// 創建密碼文件
    		File pwdFile = new File(path + File.separator + username + '.pwd');
    		pwdFile.createNewFile();
    		BufferedWriter out = new BufferedWriter(new FileWriter(pwdFile));
    		out.write(password);
    		out.flush();
    		out.close();
    	} catch (Exception e) {
    		throw new Exception('用戶  ' + username + ' 證書創建失。' + e.getMessage());
    	} finally {
    		if (fileOutputStream != null) {
    			try {
    				fileOutputStream.close();
    			} catch (IOException e) {
    			}
    		}
    	}
    }
    

      證書創建在服務器上,用戶調用下載證書的接口服務,應該返回一個下載地址,這里介紹用nginx作為文件下載服務器,參考http://www.cnblogs.com/ywlaker/p/6129872.html一文介紹的關于nginx的部分

      到此為止,ejbca構建的ca系統已經完成,當然,上述只是核心代碼,怎么運行、部署就不介紹了,下面簡單介紹https基本原理與數字證書的使用

    https基本原理與數字證書的使用

      首先,介紹下密碼學的基本知識,我們從下面的加密通信模型開始

      我向朋友發送一條消息“有時間一起吃飯嗎”,實際在網絡中傳輸的是加密后的數據,而不是原文,只是加密和解密過程對我和朋友是透明的

    1、對稱與非對稱加密

      上述通信過程中,如果加密與解密使用相同的密鑰,稱為對稱加密,如果使用不同的密鑰,稱為非對稱加密

      對稱加密的特點是速度快,可加密的數據量大;非對稱加密的特點是速度慢,因此只用來加密少量數據,但極難破解

      非對稱加密過程中使用的兩個不同的密鑰,一個稱為“私鑰”,一個稱為“公鑰”,它們一一對應,稱為“密鑰對”,“公鑰”可以給任何人使用,但“私鑰”必須自己保持,一旦“私鑰”泄露,這個密鑰對就應該被拋棄

      密鑰對有兩個非常重要的特點:1、“私鑰”可以導出“公鑰”,但“公鑰”無法導出“私鑰”;2、經“私鑰”加密的內容只能由“公鑰”解密,經“公鑰”加密的內容也只能由“私鑰”解密。

      這兩個特點有兩個重要用途:1、“私鑰”持有者用“私鑰”加密內容,發送給“公鑰”持有者解密,驗證“私鑰”持有者的身份。因為“公鑰”能解密的內容,只能是由“私鑰”加密的;2、“公鑰”持有者用“公鑰”加密內容,發送給“私鑰”持有者解密,保證內容